PostgreSQL Source Code git master
typecmds.h File Reference
#include "access/htup.h"
#include "catalog/dependency.h"
#include "parser/parse_node.h"
Include dependency graph for typecmds.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define DEFAULT_TYPDELIM   ','
 

Functions

ObjectAddress DefineType (ParseState *pstate, List *names, List *parameters)
 
void RemoveTypeById (Oid typeOid)
 
ObjectAddress DefineDomain (ParseState *pstate, CreateDomainStmt *stmt)
 
ObjectAddress DefineEnum (CreateEnumStmt *stmt)
 
ObjectAddress DefineRange (ParseState *pstate, CreateRangeStmt *stmt)
 
ObjectAddress AlterEnum (AlterEnumStmt *stmt)
 
ObjectAddress DefineCompositeType (RangeVar *typevar, List *coldeflist)
 
Oid AssignTypeArrayOid (void)
 
Oid AssignTypeMultirangeOid (void)
 
Oid AssignTypeMultirangeArrayOid (void)
 
ObjectAddress AlterDomainDefault (List *names, Node *defaultRaw)
 
ObjectAddress AlterDomainNotNull (List *names, bool notNull)
 
ObjectAddress AlterDomainAddConstraint (List *names, Node *newConstraint, ObjectAddress *constrAddr)
 
ObjectAddress AlterDomainValidateConstraint (List *names, const char *constrName)
 
ObjectAddress AlterDomainDropConstraint (List *names, const char *constrName, DropBehavior behavior, bool missing_ok)
 
void checkDomainOwner (HeapTuple tup)
 
ObjectAddress RenameType (RenameStmt *stmt)
 
ObjectAddress AlterTypeOwner (List *names, Oid newOwnerId, ObjectType objecttype)
 
void AlterTypeOwner_oid (Oid typeOid, Oid newOwnerId, bool hasDependEntry)
 
void AlterTypeOwnerInternal (Oid typeOid, Oid newOwnerId)
 
ObjectAddress AlterTypeNamespace (List *names, const char *newschema, ObjectType objecttype, Oid *oldschema)
 
Oid AlterTypeNamespace_oid (Oid typeOid, Oid nspOid, bool ignoreDependent, ObjectAddresses *objsMoved)
 
Oid AlterTypeNamespaceInternal (Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
 
ObjectAddress AlterType (AlterTypeStmt *stmt)
 

Macro Definition Documentation

◆ DEFAULT_TYPDELIM

#define DEFAULT_TYPDELIM   ','

Definition at line 22 of file typecmds.h.

Function Documentation

◆ AlterDomainAddConstraint()

ObjectAddress AlterDomainAddConstraint ( List names,
Node newConstraint,
ObjectAddress constrAddr 
)

Definition at line 2938 of file typecmds.c.

2940{
2941 TypeName *typename;
2942 Oid domainoid;
2943 Relation typrel;
2944 HeapTuple tup;
2945 Form_pg_type typTup;
2946 Constraint *constr;
2947 char *ccbin;
2949
2950 /* Make a TypeName so we can use standard type lookup machinery */
2951 typename = makeTypeNameFromNameList(names);
2952 domainoid = typenameTypeId(NULL, typename);
2953
2954 /* Look up the domain in the type table */
2955 typrel = table_open(TypeRelationId, RowExclusiveLock);
2956
2957 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2958 if (!HeapTupleIsValid(tup))
2959 elog(ERROR, "cache lookup failed for type %u", domainoid);
2960 typTup = (Form_pg_type) GETSTRUCT(tup);
2961
2962 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2963 checkDomainOwner(tup);
2964
2965 if (!IsA(newConstraint, Constraint))
2966 elog(ERROR, "unrecognized node type: %d",
2967 (int) nodeTag(newConstraint));
2968
2969 constr = (Constraint *) newConstraint;
2970
2971 /* enforced by parser */
2972 Assert(constr->contype == CONSTR_CHECK || constr->contype == CONSTR_NOTNULL);
2973
2974 if (constr->contype == CONSTR_CHECK)
2975 {
2976 /*
2977 * First, process the constraint expression and add an entry to
2978 * pg_constraint.
2979 */
2980
2981 ccbin = domainAddCheckConstraint(domainoid, typTup->typnamespace,
2982 typTup->typbasetype, typTup->typtypmod,
2983 constr, NameStr(typTup->typname), constrAddr);
2984
2985
2986 /*
2987 * If requested to validate the constraint, test all values stored in
2988 * the attributes based on the domain the constraint is being added
2989 * to.
2990 */
2991 if (!constr->skip_validation)
2992 validateDomainCheckConstraint(domainoid, ccbin, ShareLock);
2993
2994 /*
2995 * We must send out an sinval message for the domain, to ensure that
2996 * any dependent plans get rebuilt. Since this command doesn't change
2997 * the domain's pg_type row, that won't happen automatically; do it
2998 * manually.
2999 */
3000 CacheInvalidateHeapTuple(typrel, tup, NULL);
3001 }
3002 else if (constr->contype == CONSTR_NOTNULL)
3003 {
3004 /* Is the domain already set NOT NULL? */
3005 if (typTup->typnotnull)
3006 {
3008 return address;
3009 }
3010 domainAddNotNullConstraint(domainoid, typTup->typnamespace,
3011 typTup->typbasetype, typTup->typtypmod,
3012 constr, NameStr(typTup->typname), constrAddr);
3013
3014 if (!constr->skip_validation)
3016
3017 typTup->typnotnull = true;
3018 CatalogTupleUpdate(typrel, &tup->t_self, tup);
3019 }
3020
3021 ObjectAddressSet(address, TypeRelationId, domainoid);
3022
3023 /* Clean up */
3025
3026 return address;
3027}
#define NameStr(name)
Definition: c.h:754
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
Assert(PointerIsAligned(start, uint64))
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition: indexing.c:313
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1571
#define ShareLock
Definition: lockdefs.h:40
#define RowExclusiveLock
Definition: lockdefs.h:38
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:531
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define nodeTag(nodeptr)
Definition: nodes.h:139
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
@ CONSTR_NOTNULL
Definition: parsenodes.h:2801
@ CONSTR_CHECK
Definition: parsenodes.h:2805
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
unsigned int Oid
Definition: postgres_ext.h:32
ConstrType contype
Definition: parsenodes.h:2833
bool skip_validation
Definition: parsenodes.h:2838
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static char * domainAddCheckConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:3519
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3499
static void domainAddNotNullConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:3679
static void validateDomainNotNullConstraint(Oid domainoid)
Definition: typecmds.c:3139
static void validateDomainCheckConstraint(Oid domainoid, const char *ccbin, LOCKMODE lockmode)
Definition: typecmds.c:3211

References Assert(), CacheInvalidateHeapTuple(), CatalogTupleUpdate(), checkDomainOwner(), CONSTR_CHECK, CONSTR_NOTNULL, Constraint::contype, domainAddCheckConstraint(), domainAddNotNullConstraint(), elog, ERROR, GETSTRUCT(), HeapTupleIsValid, InvalidObjectAddress, IsA, makeTypeNameFromNameList(), NameStr, nodeTag, ObjectAddressSet, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheCopy1, ShareLock, Constraint::skip_validation, HeapTupleData::t_self, table_close(), table_open(), typenameTypeId(), validateDomainCheckConstraint(), and validateDomainNotNullConstraint().

Referenced by ATExecCmd(), and ProcessUtilitySlow().

◆ AlterDomainDefault()

ObjectAddress AlterDomainDefault ( List names,
Node defaultRaw 
)

Definition at line 2617 of file typecmds.c.

2618{
2619 TypeName *typename;
2620 Oid domainoid;
2621 HeapTuple tup;
2622 ParseState *pstate;
2623 Relation rel;
2624 char *defaultValue;
2625 Node *defaultExpr = NULL; /* NULL if no default specified */
2626 Datum new_record[Natts_pg_type] = {0};
2627 bool new_record_nulls[Natts_pg_type] = {0};
2628 bool new_record_repl[Natts_pg_type] = {0};
2629 HeapTuple newtuple;
2630 Form_pg_type typTup;
2631 ObjectAddress address;
2632
2633 /* Make a TypeName so we can use standard type lookup machinery */
2634 typename = makeTypeNameFromNameList(names);
2635 domainoid = typenameTypeId(NULL, typename);
2636
2637 /* Look up the domain in the type table */
2638 rel = table_open(TypeRelationId, RowExclusiveLock);
2639
2640 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2641 if (!HeapTupleIsValid(tup))
2642 elog(ERROR, "cache lookup failed for type %u", domainoid);
2643 typTup = (Form_pg_type) GETSTRUCT(tup);
2644
2645 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2646 checkDomainOwner(tup);
2647
2648 /* Setup new tuple */
2649
2650 /* Store the new default into the tuple */
2651 if (defaultRaw)
2652 {
2653 /* Create a dummy ParseState for transformExpr */
2654 pstate = make_parsestate(NULL);
2655
2656 /*
2657 * Cook the colDef->raw_expr into an expression. Note: Name is
2658 * strictly for error message
2659 */
2660 defaultExpr = cookDefault(pstate, defaultRaw,
2661 typTup->typbasetype,
2662 typTup->typtypmod,
2663 NameStr(typTup->typname),
2664 0);
2665
2666 /*
2667 * If the expression is just a NULL constant, we treat the command
2668 * like ALTER ... DROP DEFAULT. (But see note for same test in
2669 * DefineDomain.)
2670 */
2671 if (defaultExpr == NULL ||
2672 (IsA(defaultExpr, Const) && ((Const *) defaultExpr)->constisnull))
2673 {
2674 /* Default is NULL, drop it */
2675 defaultExpr = NULL;
2676 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2677 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2678 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2679 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2680 }
2681 else
2682 {
2683 /*
2684 * Expression must be stored as a nodeToString result, but we also
2685 * require a valid textual representation (mainly to make life
2686 * easier for pg_dump).
2687 */
2688 defaultValue = deparse_expression(defaultExpr,
2689 NIL, false, false);
2690
2691 /*
2692 * Form an updated tuple with the new default and write it back.
2693 */
2694 new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2695
2696 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2697 new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2698 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2699 }
2700 }
2701 else
2702 {
2703 /* ALTER ... DROP DEFAULT */
2704 new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2705 new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2706 new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2707 new_record_repl[Anum_pg_type_typdefault - 1] = true;
2708 }
2709
2710 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2711 new_record, new_record_nulls,
2712 new_record_repl);
2713
2714 CatalogTupleUpdate(rel, &tup->t_self, newtuple);
2715
2716 /* Rebuild dependencies */
2717 GenerateTypeDependencies(newtuple,
2718 rel,
2719 defaultExpr,
2720 NULL, /* don't have typacl handy */
2721 0, /* relation kind is n/a */
2722 false, /* a domain isn't an implicit array */
2723 false, /* nor is it any kind of dependent type */
2724 false, /* don't touch extension membership */
2725 true); /* We do need to rebuild dependencies */
2726
2727 InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2728
2729 ObjectAddressSet(address, TypeRelationId, domainoid);
2730
2731 /* Clean up */
2733 heap_freetuple(newtuple);
2734
2735 return address;
2736}
#define CStringGetTextDatum(s)
Definition: builtins.h:97
Node * cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
Definition: heap.c:3320
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
char * nodeToString(const void *obj)
Definition: outfuncs.c:802
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:39
#define NIL
Definition: pg_list.h:68
void GenerateTypeDependencies(HeapTuple typeTuple, Relation typeCatalog, Node *defaultExpr, void *typacl, char relationKind, bool isImplicitArray, bool isDependentType, bool makeExtensionDep, bool rebuild)
Definition: pg_type.c:555
uint64_t Datum
Definition: postgres.h:70
#define RelationGetDescr(relation)
Definition: rel.h:541
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3648
Definition: nodes.h:135

References CatalogTupleUpdate(), checkDomainOwner(), cookDefault(), CStringGetTextDatum, deparse_expression(), elog, ERROR, GenerateTypeDependencies(), GETSTRUCT(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, IsA, make_parsestate(), makeTypeNameFromNameList(), NameStr, NIL, nodeToString(), ObjectAddressSet, ObjectIdGetDatum(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), table_open(), and typenameTypeId().

Referenced by ProcessUtilitySlow().

◆ AlterDomainDropConstraint()

ObjectAddress AlterDomainDropConstraint ( List names,
const char *  constrName,
DropBehavior  behavior,
bool  missing_ok 
)

Definition at line 2832 of file typecmds.c.

2834{
2835 TypeName *typename;
2836 Oid domainoid;
2837 HeapTuple tup;
2838 Relation rel;
2839 Relation conrel;
2840 SysScanDesc conscan;
2841 ScanKeyData skey[3];
2842 HeapTuple contup;
2843 bool found = false;
2844 ObjectAddress address;
2845
2846 /* Make a TypeName so we can use standard type lookup machinery */
2847 typename = makeTypeNameFromNameList(names);
2848 domainoid = typenameTypeId(NULL, typename);
2849
2850 /* Look up the domain in the type table */
2851 rel = table_open(TypeRelationId, RowExclusiveLock);
2852
2853 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2854 if (!HeapTupleIsValid(tup))
2855 elog(ERROR, "cache lookup failed for type %u", domainoid);
2856
2857 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2858 checkDomainOwner(tup);
2859
2860 /* Grab an appropriate lock on the pg_constraint relation */
2861 conrel = table_open(ConstraintRelationId, RowExclusiveLock);
2862
2863 /* Find and remove the target constraint */
2864 ScanKeyInit(&skey[0],
2865 Anum_pg_constraint_conrelid,
2866 BTEqualStrategyNumber, F_OIDEQ,
2868 ScanKeyInit(&skey[1],
2869 Anum_pg_constraint_contypid,
2870 BTEqualStrategyNumber, F_OIDEQ,
2871 ObjectIdGetDatum(domainoid));
2872 ScanKeyInit(&skey[2],
2873 Anum_pg_constraint_conname,
2874 BTEqualStrategyNumber, F_NAMEEQ,
2875 CStringGetDatum(constrName));
2876
2877 conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
2878 NULL, 3, skey);
2879
2880 /* There can be at most one matching row */
2881 if ((contup = systable_getnext(conscan)) != NULL)
2882 {
2883 Form_pg_constraint construct = (Form_pg_constraint) GETSTRUCT(contup);
2884 ObjectAddress conobj;
2885
2886 if (construct->contype == CONSTRAINT_NOTNULL)
2887 {
2888 ((Form_pg_type) GETSTRUCT(tup))->typnotnull = false;
2889 CatalogTupleUpdate(rel, &tup->t_self, tup);
2890 }
2891
2892 conobj.classId = ConstraintRelationId;
2893 conobj.objectId = construct->oid;
2894 conobj.objectSubId = 0;
2895
2896 performDeletion(&conobj, behavior, 0);
2897 found = true;
2898 }
2899
2900 /* Clean up after the scan */
2901 systable_endscan(conscan);
2903
2904 if (!found)
2905 {
2906 if (!missing_ok)
2907 ereport(ERROR,
2908 (errcode(ERRCODE_UNDEFINED_OBJECT),
2909 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2910 constrName, TypeNameToString(typename))));
2911 else
2913 (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2914 constrName, TypeNameToString(typename))));
2915 }
2916
2917 /*
2918 * We must send out an sinval message for the domain, to ensure that any
2919 * dependent plans get rebuilt. Since this command doesn't change the
2920 * domain's pg_type row, that won't happen automatically; do it manually.
2921 */
2922 CacheInvalidateHeapTuple(rel, tup, NULL);
2923
2924 ObjectAddressSet(address, TypeRelationId, domainoid);
2925
2926 /* Clean up */
2928
2929 return address;
2930}
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:274
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:150
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:478
FormData_pg_constraint * Form_pg_constraint
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:360
#define InvalidOid
Definition: postgres_ext.h:37
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31

References BTEqualStrategyNumber, CacheInvalidateHeapTuple(), CatalogTupleUpdate(), checkDomainOwner(), ObjectAddress::classId, CStringGetDatum(), elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT(), HeapTupleIsValid, InvalidOid, makeTypeNameFromNameList(), NOTICE, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, performDeletion(), RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), TypeNameToString(), and typenameTypeId().

Referenced by ProcessUtilitySlow().

◆ AlterDomainNotNull()

ObjectAddress AlterDomainNotNull ( List names,
bool  notNull 
)

Definition at line 2746 of file typecmds.c.

2747{
2748 TypeName *typename;
2749 Oid domainoid;
2750 Relation typrel;
2751 HeapTuple tup;
2752 Form_pg_type typTup;
2754
2755 /* Make a TypeName so we can use standard type lookup machinery */
2756 typename = makeTypeNameFromNameList(names);
2757 domainoid = typenameTypeId(NULL, typename);
2758
2759 /* Look up the domain in the type table */
2760 typrel = table_open(TypeRelationId, RowExclusiveLock);
2761
2762 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2763 if (!HeapTupleIsValid(tup))
2764 elog(ERROR, "cache lookup failed for type %u", domainoid);
2765 typTup = (Form_pg_type) GETSTRUCT(tup);
2766
2767 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2768 checkDomainOwner(tup);
2769
2770 /* Is the domain already set to the desired constraint? */
2771 if (typTup->typnotnull == notNull)
2772 {
2774 return address;
2775 }
2776
2777 if (notNull)
2778 {
2779 Constraint *constr;
2780
2781 constr = makeNode(Constraint);
2782 constr->contype = CONSTR_NOTNULL;
2783 constr->initially_valid = true;
2784 constr->location = -1;
2785
2786 domainAddNotNullConstraint(domainoid, typTup->typnamespace,
2787 typTup->typbasetype, typTup->typtypmod,
2788 constr, NameStr(typTup->typname), NULL);
2789
2791 }
2792 else
2793 {
2794 HeapTuple conTup;
2795 ObjectAddress conobj;
2796
2797 conTup = findDomainNotNullConstraint(domainoid);
2798 if (conTup == NULL)
2799 elog(ERROR, "could not find not-null constraint on domain \"%s\"", NameStr(typTup->typname));
2800
2801 ObjectAddressSet(conobj, ConstraintRelationId, ((Form_pg_constraint) GETSTRUCT(conTup))->oid);
2802 performDeletion(&conobj, DROP_RESTRICT, 0);
2803 }
2804
2805 /*
2806 * Okay to update pg_type row. We can scribble on typTup because it's a
2807 * copy.
2808 */
2809 typTup->typnotnull = notNull;
2810
2811 CatalogTupleUpdate(typrel, &tup->t_self, tup);
2812
2813 InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2814
2815 ObjectAddressSet(address, TypeRelationId, domainoid);
2816
2817 /* Clean up */
2818 heap_freetuple(tup);
2820
2821 return address;
2822}
#define makeNode(_type_)
Definition: nodes.h:161
@ DROP_RESTRICT
Definition: parsenodes.h:2398
HeapTuple findDomainNotNullConstraint(Oid typid)
ParseLoc location
Definition: parsenodes.h:2877
bool initially_valid
Definition: parsenodes.h:2839

References CatalogTupleUpdate(), checkDomainOwner(), CONSTR_NOTNULL, Constraint::contype, domainAddNotNullConstraint(), DROP_RESTRICT, elog, ERROR, findDomainNotNullConstraint(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, Constraint::initially_valid, InvalidObjectAddress, InvokeObjectPostAlterHook, Constraint::location, makeNode, makeTypeNameFromNameList(), NameStr, ObjectAddressSet, ObjectIdGetDatum(), performDeletion(), RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), table_open(), typenameTypeId(), and validateDomainNotNullConstraint().

Referenced by ProcessUtilitySlow().

◆ AlterDomainValidateConstraint()

ObjectAddress AlterDomainValidateConstraint ( List names,
const char *  constrName 
)

Definition at line 3035 of file typecmds.c.

3036{
3037 TypeName *typename;
3038 Oid domainoid;
3039 Relation typrel;
3040 Relation conrel;
3041 HeapTuple tup;
3043 Form_pg_constraint copy_con;
3044 char *conbin;
3045 SysScanDesc scan;
3046 Datum val;
3047 HeapTuple tuple;
3048 HeapTuple copyTuple;
3049 ScanKeyData skey[3];
3050 ObjectAddress address;
3051
3052 /* Make a TypeName so we can use standard type lookup machinery */
3053 typename = makeTypeNameFromNameList(names);
3054 domainoid = typenameTypeId(NULL, typename);
3055
3056 /* Look up the domain in the type table */
3057 typrel = table_open(TypeRelationId, AccessShareLock);
3058
3059 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
3060 if (!HeapTupleIsValid(tup))
3061 elog(ERROR, "cache lookup failed for type %u", domainoid);
3062
3063 /* Check it's a domain and check user has permission for ALTER DOMAIN */
3064 checkDomainOwner(tup);
3065
3066 /*
3067 * Find and check the target constraint
3068 */
3069 conrel = table_open(ConstraintRelationId, RowExclusiveLock);
3070
3071 ScanKeyInit(&skey[0],
3072 Anum_pg_constraint_conrelid,
3073 BTEqualStrategyNumber, F_OIDEQ,
3075 ScanKeyInit(&skey[1],
3076 Anum_pg_constraint_contypid,
3077 BTEqualStrategyNumber, F_OIDEQ,
3078 ObjectIdGetDatum(domainoid));
3079 ScanKeyInit(&skey[2],
3080 Anum_pg_constraint_conname,
3081 BTEqualStrategyNumber, F_NAMEEQ,
3082 CStringGetDatum(constrName));
3083
3084 scan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
3085 NULL, 3, skey);
3086
3087 /* There can be at most one matching row */
3088 if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
3089 ereport(ERROR,
3090 (errcode(ERRCODE_UNDEFINED_OBJECT),
3091 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
3092 constrName, TypeNameToString(typename))));
3093
3094 con = (Form_pg_constraint) GETSTRUCT(tuple);
3095 if (con->contype != CONSTRAINT_CHECK)
3096 ereport(ERROR,
3097 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3098 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
3099 constrName, TypeNameToString(typename))));
3100
3101 val = SysCacheGetAttrNotNull(CONSTROID, tuple, Anum_pg_constraint_conbin);
3102 conbin = TextDatumGetCString(val);
3103
3104 /*
3105 * Locking related relations with ShareUpdateExclusiveLock is ok because
3106 * not-yet-valid constraints are still enforced against concurrent inserts
3107 * or updates.
3108 */
3110
3111 /*
3112 * Now update the catalog, while we have the door open.
3113 */
3114 copyTuple = heap_copytuple(tuple);
3115 copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
3116 copy_con->convalidated = true;
3117 CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
3118
3119 InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
3120
3121 ObjectAddressSet(address, TypeRelationId, domainoid);
3122
3123 heap_freetuple(copyTuple);
3124
3125 systable_endscan(scan);
3126
3129
3130 ReleaseSysCache(tup);
3131
3132 return address;
3133}
#define TextDatumGetCString(d)
Definition: builtins.h:98
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:778
long val
Definition: informix.c:689
#define AccessShareLock
Definition: lockdefs.h:36
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220
Datum SysCacheGetAttrNotNull(int cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition: syscache.c:625

References AccessShareLock, BTEqualStrategyNumber, CatalogTupleUpdate(), checkDomainOwner(), CStringGetDatum(), elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT(), heap_copytuple(), heap_freetuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHook, makeTypeNameFromNameList(), ObjectAddressSet, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), ShareUpdateExclusiveLock, SysCacheGetAttrNotNull(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), TextDatumGetCString, TypeNameToString(), typenameTypeId(), val, and validateDomainCheckConstraint().

Referenced by ProcessUtilitySlow().

◆ AlterEnum()

ObjectAddress AlterEnum ( AlterEnumStmt stmt)

Definition at line 1305 of file typecmds.c.

1306{
1307 Oid enum_type_oid;
1308 TypeName *typename;
1309 HeapTuple tup;
1310 ObjectAddress address;
1311
1312 /* Make a TypeName so we can use standard type lookup machinery */
1313 typename = makeTypeNameFromNameList(stmt->typeName);
1314 enum_type_oid = typenameTypeId(NULL, typename);
1315
1316 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1317 if (!HeapTupleIsValid(tup))
1318 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1319
1320 /* Check it's an enum and check user has permission to ALTER the enum */
1321 checkEnumOwner(tup);
1322
1323 ReleaseSysCache(tup);
1324
1325 if (stmt->oldVal)
1326 {
1327 /* Rename an existing label */
1328 RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
1329 }
1330 else
1331 {
1332 /* Add a new label */
1333 AddEnumLabel(enum_type_oid, stmt->newVal,
1334 stmt->newValNeighbor, stmt->newValIsAfter,
1335 stmt->skipIfNewValExists);
1336 }
1337
1338 InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1339
1340 ObjectAddressSet(address, TypeRelationId, enum_type_oid);
1341
1342 return address;
1343}
#define stmt
Definition: indent_codes.h:59
void RenameEnumLabel(Oid enumTypeOid, const char *oldVal, const char *newVal)
Definition: pg_enum.c:620
void AddEnumLabel(Oid enumTypeOid, const char *newVal, const char *neighbor, bool newValIsAfter, bool skipIfExists)
Definition: pg_enum.c:305
static void checkEnumOwner(HeapTuple tup)
Definition: typecmds.c:1353

References AddEnumLabel(), checkEnumOwner(), elog, ERROR, HeapTupleIsValid, InvokeObjectPostAlterHook, makeTypeNameFromNameList(), ObjectAddressSet, ObjectIdGetDatum(), ReleaseSysCache(), RenameEnumLabel(), SearchSysCache1(), stmt, and typenameTypeId().

Referenced by ProcessUtilitySlow().

◆ AlterType()

ObjectAddress AlterType ( AlterTypeStmt stmt)

Definition at line 4325 of file typecmds.c.

4326{
4327 ObjectAddress address;
4328 Relation catalog;
4329 TypeName *typename;
4330 HeapTuple tup;
4331 Oid typeOid;
4332 Form_pg_type typForm;
4333 bool requireSuper = false;
4334 AlterTypeRecurseParams atparams;
4335 ListCell *pl;
4336
4337 catalog = table_open(TypeRelationId, RowExclusiveLock);
4338
4339 /* Make a TypeName so we can use standard type lookup machinery */
4340 typename = makeTypeNameFromNameList(stmt->typeName);
4341 tup = typenameType(NULL, typename, NULL);
4342
4343 typeOid = typeTypeId(tup);
4344 typForm = (Form_pg_type) GETSTRUCT(tup);
4345
4346 /* Process options */
4347 memset(&atparams, 0, sizeof(atparams));
4348 foreach(pl, stmt->options)
4349 {
4350 DefElem *defel = (DefElem *) lfirst(pl);
4351
4352 if (strcmp(defel->defname, "storage") == 0)
4353 {
4354 char *a = defGetString(defel);
4355
4356 if (pg_strcasecmp(a, "plain") == 0)
4357 atparams.storage = TYPSTORAGE_PLAIN;
4358 else if (pg_strcasecmp(a, "external") == 0)
4359 atparams.storage = TYPSTORAGE_EXTERNAL;
4360 else if (pg_strcasecmp(a, "extended") == 0)
4361 atparams.storage = TYPSTORAGE_EXTENDED;
4362 else if (pg_strcasecmp(a, "main") == 0)
4363 atparams.storage = TYPSTORAGE_MAIN;
4364 else
4365 ereport(ERROR,
4366 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4367 errmsg("storage \"%s\" not recognized", a)));
4368
4369 /*
4370 * Validate the storage request. If the type isn't varlena, it
4371 * certainly doesn't support non-PLAIN storage.
4372 */
4373 if (atparams.storage != TYPSTORAGE_PLAIN && typForm->typlen != -1)
4374 ereport(ERROR,
4375 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
4376 errmsg("fixed-size types must have storage PLAIN")));
4377
4378 /*
4379 * Switching from PLAIN to non-PLAIN is allowed, but it requires
4380 * superuser, since we can't validate that the type's C functions
4381 * will support it. Switching from non-PLAIN to PLAIN is
4382 * disallowed outright, because it's not practical to ensure that
4383 * no tables have toasted values of the type. Switching among
4384 * different non-PLAIN settings is OK, since it just constitutes a
4385 * change in the strategy requested for columns created in the
4386 * future.
4387 */
4388 if (atparams.storage != TYPSTORAGE_PLAIN &&
4389 typForm->typstorage == TYPSTORAGE_PLAIN)
4390 requireSuper = true;
4391 else if (atparams.storage == TYPSTORAGE_PLAIN &&
4392 typForm->typstorage != TYPSTORAGE_PLAIN)
4393 ereport(ERROR,
4394 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
4395 errmsg("cannot change type's storage to PLAIN")));
4396
4397 atparams.updateStorage = true;
4398 }
4399 else if (strcmp(defel->defname, "receive") == 0)
4400 {
4401 if (defel->arg != NULL)
4402 atparams.receiveOid =
4404 typeOid);
4405 else
4406 atparams.receiveOid = InvalidOid; /* NONE, remove function */
4407 atparams.updateReceive = true;
4408 /* Replacing an I/O function requires superuser. */
4409 requireSuper = true;
4410 }
4411 else if (strcmp(defel->defname, "send") == 0)
4412 {
4413 if (defel->arg != NULL)
4414 atparams.sendOid =
4416 typeOid);
4417 else
4418 atparams.sendOid = InvalidOid; /* NONE, remove function */
4419 atparams.updateSend = true;
4420 /* Replacing an I/O function requires superuser. */
4421 requireSuper = true;
4422 }
4423 else if (strcmp(defel->defname, "typmod_in") == 0)
4424 {
4425 if (defel->arg != NULL)
4426 atparams.typmodinOid =
4428 else
4429 atparams.typmodinOid = InvalidOid; /* NONE, remove function */
4430 atparams.updateTypmodin = true;
4431 /* Replacing an I/O function requires superuser. */
4432 requireSuper = true;
4433 }
4434 else if (strcmp(defel->defname, "typmod_out") == 0)
4435 {
4436 if (defel->arg != NULL)
4437 atparams.typmodoutOid =
4439 else
4440 atparams.typmodoutOid = InvalidOid; /* NONE, remove function */
4441 atparams.updateTypmodout = true;
4442 /* Replacing an I/O function requires superuser. */
4443 requireSuper = true;
4444 }
4445 else if (strcmp(defel->defname, "analyze") == 0)
4446 {
4447 if (defel->arg != NULL)
4448 atparams.analyzeOid =
4450 typeOid);
4451 else
4452 atparams.analyzeOid = InvalidOid; /* NONE, remove function */
4453 atparams.updateAnalyze = true;
4454 /* Replacing an analyze function requires superuser. */
4455 requireSuper = true;
4456 }
4457 else if (strcmp(defel->defname, "subscript") == 0)
4458 {
4459 if (defel->arg != NULL)
4460 atparams.subscriptOid =
4462 typeOid);
4463 else
4464 atparams.subscriptOid = InvalidOid; /* NONE, remove function */
4465 atparams.updateSubscript = true;
4466 /* Replacing a subscript function requires superuser. */
4467 requireSuper = true;
4468 }
4469
4470 /*
4471 * The rest of the options that CREATE accepts cannot be changed.
4472 * Check for them so that we can give a meaningful error message.
4473 */
4474 else if (strcmp(defel->defname, "input") == 0 ||
4475 strcmp(defel->defname, "output") == 0 ||
4476 strcmp(defel->defname, "internallength") == 0 ||
4477 strcmp(defel->defname, "passedbyvalue") == 0 ||
4478 strcmp(defel->defname, "alignment") == 0 ||
4479 strcmp(defel->defname, "like") == 0 ||
4480 strcmp(defel->defname, "category") == 0 ||
4481 strcmp(defel->defname, "preferred") == 0 ||
4482 strcmp(defel->defname, "default") == 0 ||
4483 strcmp(defel->defname, "element") == 0 ||
4484 strcmp(defel->defname, "delimiter") == 0 ||
4485 strcmp(defel->defname, "collatable") == 0)
4486 ereport(ERROR,
4487 (errcode(ERRCODE_SYNTAX_ERROR),
4488 errmsg("type attribute \"%s\" cannot be changed",
4489 defel->defname)));
4490 else
4491 ereport(ERROR,
4492 (errcode(ERRCODE_SYNTAX_ERROR),
4493 errmsg("type attribute \"%s\" not recognized",
4494 defel->defname)));
4495 }
4496
4497 /*
4498 * Permissions check. Require superuser if we decided the command
4499 * requires that, else must own the type.
4500 */
4501 if (requireSuper)
4502 {
4503 if (!superuser())
4504 ereport(ERROR,
4505 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
4506 errmsg("must be superuser to alter a type")));
4507 }
4508 else
4509 {
4510 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
4512 }
4513
4514 /*
4515 * We disallow all forms of ALTER TYPE SET on types that aren't plain base
4516 * types. It would for example be highly unsafe, not to mention
4517 * pointless, to change the send/receive functions for a composite type.
4518 * Moreover, pg_dump has no support for changing these properties on
4519 * non-base types. We might weaken this someday, but not now.
4520 *
4521 * Note: if you weaken this enough to allow composite types, be sure to
4522 * adjust the GenerateTypeDependencies call in AlterTypeRecurse.
4523 */
4524 if (typForm->typtype != TYPTYPE_BASE)
4525 ereport(ERROR,
4526 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4527 errmsg("%s is not a base type",
4528 format_type_be(typeOid))));
4529
4530 /*
4531 * For the same reasons, don't allow direct alteration of array types.
4532 */
4533 if (IsTrueArrayType(typForm))
4534 ereport(ERROR,
4535 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4536 errmsg("%s is not a base type",
4537 format_type_be(typeOid))));
4538
4539 /* OK, recursively update this type and any arrays/domains over it */
4540 AlterTypeRecurse(typeOid, false, tup, catalog, &atparams);
4541
4542 /* Clean up */
4543 ReleaseSysCache(tup);
4544
4545 table_close(catalog, RowExclusiveLock);
4546
4547 ObjectAddressSet(address, TypeRelationId, typeOid);
4548
4549 return address;
4550}
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4088
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:2971
char * defGetString(DefElem *def)
Definition: define.c:35
List * defGetQualifiedName(DefElem *def)
Definition: define.c:239
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
int a
Definition: isn.c:73
Oid GetUserId(void)
Definition: miscinit.c:469
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
Oid typeTypeId(Type tp)
Definition: parse_type.c:590
#define lfirst(lc)
Definition: pg_list.h:172
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:32
char * defname
Definition: parsenodes.h:843
Node * arg
Definition: parsenodes.h:844
bool superuser(void)
Definition: superuser.c:46
static Oid findTypeReceiveFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2092
static void AlterTypeRecurse(Oid typeOid, bool isImplicitArray, HeapTuple tup, Relation catalog, AlterTypeRecurseParams *atparams)
Definition: typecmds.c:4576
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2249
static Oid findTypeSendFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2146
static Oid findTypeSubscriptingFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2276
static Oid findTypeTypmodoutFunction(List *procname)
Definition: typecmds.c:2215
static Oid findTypeTypmodinFunction(List *procname)
Definition: typecmds.c:2181

References a, aclcheck_error_type(), ACLCHECK_NOT_OWNER, AlterTypeRecurse(), AlterTypeRecurseParams::analyzeOid, DefElem::arg, defGetQualifiedName(), defGetString(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, findTypeAnalyzeFunction(), findTypeReceiveFunction(), findTypeSendFunction(), findTypeSubscriptingFunction(), findTypeTypmodinFunction(), findTypeTypmodoutFunction(), format_type_be(), GETSTRUCT(), GetUserId(), InvalidOid, lfirst, makeTypeNameFromNameList(), object_ownercheck(), ObjectAddressSet, pg_strcasecmp(), AlterTypeRecurseParams::receiveOid, ReleaseSysCache(), RowExclusiveLock, AlterTypeRecurseParams::sendOid, stmt, AlterTypeRecurseParams::storage, AlterTypeRecurseParams::subscriptOid, superuser(), table_close(), table_open(), typenameType(), typeTypeId(), AlterTypeRecurseParams::typmodinOid, AlterTypeRecurseParams::typmodoutOid, AlterTypeRecurseParams::updateAnalyze, AlterTypeRecurseParams::updateReceive, AlterTypeRecurseParams::updateSend, AlterTypeRecurseParams::updateStorage, AlterTypeRecurseParams::updateSubscript, AlterTypeRecurseParams::updateTypmodin, and AlterTypeRecurseParams::updateTypmodout.

Referenced by ProcessUtilitySlow().

◆ AlterTypeNamespace()

ObjectAddress AlterTypeNamespace ( List names,
const char *  newschema,
ObjectType  objecttype,
Oid oldschema 
)

Definition at line 4068 of file typecmds.c.

4070{
4071 TypeName *typename;
4072 Oid typeOid;
4073 Oid nspOid;
4074 Oid oldNspOid;
4075 ObjectAddresses *objsMoved;
4076 ObjectAddress myself;
4077
4078 /* Make a TypeName so we can use standard type lookup machinery */
4079 typename = makeTypeNameFromNameList(names);
4080 typeOid = typenameTypeId(NULL, typename);
4081
4082 /* Don't allow ALTER DOMAIN on a non-domain type */
4083 if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
4084 ereport(ERROR,
4085 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4086 errmsg("%s is not a domain",
4087 format_type_be(typeOid))));
4088
4089 /* get schema OID and check its permissions */
4090 nspOid = LookupCreationNamespace(newschema);
4091
4092 objsMoved = new_object_addresses();
4093 oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, false, objsMoved);
4094 free_object_addresses(objsMoved);
4095
4096 if (oldschema)
4097 *oldschema = oldNspOid;
4098
4099 ObjectAddressSet(myself, TypeRelationId, typeOid);
4100
4101 return myself;
4102}
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2615
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2901
char get_typtype(Oid typid)
Definition: lsyscache.c:2796
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:3498
@ OBJECT_DOMAIN
Definition: parsenodes.h:2337
Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, bool ignoreDependent, ObjectAddresses *objsMoved)
Definition: typecmds.c:4117

References AlterTypeNamespace_oid(), ereport, errcode(), errmsg(), ERROR, format_type_be(), free_object_addresses(), get_typtype(), LookupCreationNamespace(), makeTypeNameFromNameList(), new_object_addresses(), OBJECT_DOMAIN, ObjectAddressSet, and typenameTypeId().

Referenced by ExecAlterObjectSchemaStmt().

◆ AlterTypeNamespace_oid()

Oid AlterTypeNamespace_oid ( Oid  typeOid,
Oid  nspOid,
bool  ignoreDependent,
ObjectAddresses objsMoved 
)

Definition at line 4117 of file typecmds.c.

4119{
4120 Oid elemOid;
4121
4122 /* check permissions on type */
4123 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
4125
4126 /* don't allow direct alteration of array types */
4127 elemOid = get_element_type(typeOid);
4128 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
4129 {
4130 if (ignoreDependent)
4131 return InvalidOid;
4132 ereport(ERROR,
4133 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4134 errmsg("cannot alter array type %s",
4135 format_type_be(typeOid)),
4136 errhint("You can alter type %s, which will alter the array type as well.",
4137 format_type_be(elemOid))));
4138 }
4139
4140 /* and do the work */
4141 return AlterTypeNamespaceInternal(typeOid, nspOid,
4142 false, /* isImplicitArray */
4143 ignoreDependent, /* ignoreDependent */
4144 true, /* errorOnTableType */
4145 objsMoved);
4146}
#define OidIsValid(objectId)
Definition: c.h:777
int errhint(const char *fmt,...)
Definition: elog.c:1330
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2926
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2954
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4169

References aclcheck_error_type(), ACLCHECK_NOT_OWNER, AlterTypeNamespaceInternal(), ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), get_array_type(), get_element_type(), GetUserId(), InvalidOid, object_ownercheck(), and OidIsValid.

Referenced by AlterObjectNamespace_oid(), and AlterTypeNamespace().

◆ AlterTypeNamespaceInternal()

Oid AlterTypeNamespaceInternal ( Oid  typeOid,
Oid  nspOid,
bool  isImplicitArray,
bool  ignoreDependent,
bool  errorOnTableType,
ObjectAddresses objsMoved 
)

Definition at line 4169 of file typecmds.c.

4174{
4175 Relation rel;
4176 HeapTuple tup;
4177 Form_pg_type typform;
4178 Oid oldNspOid;
4179 Oid arrayOid;
4180 bool isCompositeType;
4181 ObjectAddress thisobj;
4182
4183 /*
4184 * Make sure we haven't moved this object previously.
4185 */
4186 thisobj.classId = TypeRelationId;
4187 thisobj.objectId = typeOid;
4188 thisobj.objectSubId = 0;
4189
4190 if (object_address_present(&thisobj, objsMoved))
4191 return InvalidOid;
4192
4193 rel = table_open(TypeRelationId, RowExclusiveLock);
4194
4195 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
4196 if (!HeapTupleIsValid(tup))
4197 elog(ERROR, "cache lookup failed for type %u", typeOid);
4198 typform = (Form_pg_type) GETSTRUCT(tup);
4199
4200 oldNspOid = typform->typnamespace;
4201 arrayOid = typform->typarray;
4202
4203 /* If the type is already there, we scan skip these next few checks. */
4204 if (oldNspOid != nspOid)
4205 {
4206 /* common checks on switching namespaces */
4207 CheckSetNamespace(oldNspOid, nspOid);
4208
4209 /* check for duplicate name (more friendly than unique-index failure) */
4210 if (SearchSysCacheExists2(TYPENAMENSP,
4211 NameGetDatum(&typform->typname),
4212 ObjectIdGetDatum(nspOid)))
4213 ereport(ERROR,
4215 errmsg("type \"%s\" already exists in schema \"%s\"",
4216 NameStr(typform->typname),
4217 get_namespace_name(nspOid))));
4218 }
4219
4220 /* Detect whether type is a composite type (but not a table rowtype) */
4222 (typform->typtype == TYPTYPE_COMPOSITE &&
4223 get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
4224
4225 /* Enforce not-table-type if requested */
4226 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType)
4227 {
4228 if (ignoreDependent)
4229 {
4231 return InvalidOid;
4232 }
4233 if (errorOnTableType)
4234 ereport(ERROR,
4235 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4236 errmsg("%s is a table's row type",
4237 format_type_be(typeOid)),
4238 /* translator: %s is an SQL ALTER command */
4239 errhint("Use %s instead.", "ALTER TABLE")));
4240 }
4241
4242 if (oldNspOid != nspOid)
4243 {
4244 /* OK, modify the pg_type row */
4245
4246 /* tup is a copy, so we can scribble directly on it */
4247 typform->typnamespace = nspOid;
4248
4249 CatalogTupleUpdate(rel, &tup->t_self, tup);
4250 }
4251
4252 /*
4253 * Composite types have pg_class entries.
4254 *
4255 * We need to modify the pg_class tuple as well to reflect the change of
4256 * schema.
4257 */
4258 if (isCompositeType)
4259 {
4260 Relation classRel;
4261
4262 classRel = table_open(RelationRelationId, RowExclusiveLock);
4263
4264 AlterRelationNamespaceInternal(classRel, typform->typrelid,
4265 oldNspOid, nspOid,
4266 false, objsMoved);
4267
4268 table_close(classRel, RowExclusiveLock);
4269
4270 /*
4271 * Check for constraints associated with the composite type (we don't
4272 * currently support this, but probably will someday).
4273 */
4274 AlterConstraintNamespaces(typform->typrelid, oldNspOid,
4275 nspOid, false, objsMoved);
4276 }
4277 else
4278 {
4279 /* If it's a domain, it might have constraints */
4280 if (typform->typtype == TYPTYPE_DOMAIN)
4281 AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
4282 objsMoved);
4283 }
4284
4285 /*
4286 * Update dependency on schema, if any --- a table rowtype has not got
4287 * one, and neither does an implicit array.
4288 */
4289 if (oldNspOid != nspOid &&
4290 (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
4291 !isImplicitArray)
4292 if (changeDependencyFor(TypeRelationId, typeOid,
4293 NamespaceRelationId, oldNspOid, nspOid) != 1)
4294 elog(ERROR, "could not change schema dependency for type \"%s\"",
4295 format_type_be(typeOid));
4296
4297 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
4298
4299 heap_freetuple(tup);
4300
4302
4303 add_exact_object_address(&thisobj, objsMoved);
4304
4305 /* Recursively alter the associated array type, if any */
4306 if (OidIsValid(arrayOid))
4307 AlterTypeNamespaceInternal(arrayOid, nspOid,
4308 true, /* isImplicitArray */
4309 false, /* ignoreDependent */
4310 true, /* errorOnTableType */
4311 objsMoved);
4312
4313 return oldNspOid;
4314}
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2721
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2661
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2170
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3533
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3529
static bool isCompositeType(Oid typid)
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:457
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:383
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:102
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:19044

References add_exact_object_address(), AlterConstraintNamespaces(), AlterRelationNamespaceInternal(), AlterTypeNamespaceInternal(), CatalogTupleUpdate(), changeDependencyFor(), CheckSetNamespace(), ObjectAddress::classId, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg(), ERROR, format_type_be(), get_namespace_name(), get_rel_relkind(), GETSTRUCT(), heap_freetuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHook, isCompositeType(), NameGetDatum(), NameStr, object_address_present(), ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, OidIsValid, RowExclusiveLock, SearchSysCacheCopy1, SearchSysCacheExists2, HeapTupleData::t_self, table_close(), and table_open().

Referenced by AlterTableNamespaceInternal(), AlterTypeNamespace_oid(), and AlterTypeNamespaceInternal().

◆ AlterTypeOwner()

ObjectAddress AlterTypeOwner ( List names,
Oid  newOwnerId,
ObjectType  objecttype 
)

Definition at line 3835 of file typecmds.c.

3836{
3837 TypeName *typename;
3838 Oid typeOid;
3839 Relation rel;
3840 HeapTuple tup;
3841 HeapTuple newtup;
3842 Form_pg_type typTup;
3843 AclResult aclresult;
3844 ObjectAddress address;
3845
3846 rel = table_open(TypeRelationId, RowExclusiveLock);
3847
3848 /* Make a TypeName so we can use standard type lookup machinery */
3849 typename = makeTypeNameFromNameList(names);
3850
3851 /* Use LookupTypeName here so that shell types can be processed */
3852 tup = LookupTypeName(NULL, typename, NULL, false);
3853 if (tup == NULL)
3854 ereport(ERROR,
3855 (errcode(ERRCODE_UNDEFINED_OBJECT),
3856 errmsg("type \"%s\" does not exist",
3857 TypeNameToString(typename))));
3858 typeOid = typeTypeId(tup);
3859
3860 /* Copy the syscache entry so we can scribble on it below */
3861 newtup = heap_copytuple(tup);
3862 ReleaseSysCache(tup);
3863 tup = newtup;
3864 typTup = (Form_pg_type) GETSTRUCT(tup);
3865
3866 /* Don't allow ALTER DOMAIN on a type */
3867 if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3868 ereport(ERROR,
3869 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3870 errmsg("%s is not a domain",
3871 format_type_be(typeOid))));
3872
3873 /*
3874 * If it's a composite type, we need to check that it really is a
3875 * free-standing composite type, and not a table's rowtype. We want people
3876 * to use ALTER TABLE not ALTER TYPE for that case.
3877 */
3878 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3879 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3880 ereport(ERROR,
3881 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3882 errmsg("%s is a table's row type",
3883 format_type_be(typeOid)),
3884 /* translator: %s is an SQL ALTER command */
3885 errhint("Use %s instead.",
3886 "ALTER TABLE")));
3887
3888 /* don't allow direct alteration of array types, either */
3889 if (IsTrueArrayType(typTup))
3890 ereport(ERROR,
3891 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3892 errmsg("cannot alter array type %s",
3893 format_type_be(typeOid)),
3894 errhint("You can alter type %s, which will alter the array type as well.",
3895 format_type_be(typTup->typelem))));
3896
3897 /* don't allow direct alteration of multirange types, either */
3898 if (typTup->typtype == TYPTYPE_MULTIRANGE)
3899 {
3900 Oid rangetype = get_multirange_range(typeOid);
3901
3902 /* We don't expect get_multirange_range to fail, but cope if so */
3903 ereport(ERROR,
3904 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3905 errmsg("cannot alter multirange type %s",
3906 format_type_be(typeOid)),
3907 OidIsValid(rangetype) ?
3908 errhint("You can alter type %s, which will alter the multirange type as well.",
3909 format_type_be(rangetype)) : 0));
3910 }
3911
3912 /*
3913 * If the new owner is the same as the existing owner, consider the
3914 * command to have succeeded. This is for dump restoration purposes.
3915 */
3916 if (typTup->typowner != newOwnerId)
3917 {
3918 /* Superusers can always do it */
3919 if (!superuser())
3920 {
3921 /* Otherwise, must be owner of the existing object */
3922 if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
3924
3925 /* Must be able to become new owner */
3926 check_can_set_role(GetUserId(), newOwnerId);
3927
3928 /* New owner must have CREATE privilege on namespace */
3929 aclresult = object_aclcheck(NamespaceRelationId, typTup->typnamespace,
3930 newOwnerId,
3931 ACL_CREATE);
3932 if (aclresult != ACLCHECK_OK)
3933 aclcheck_error(aclresult, OBJECT_SCHEMA,
3934 get_namespace_name(typTup->typnamespace));
3935 }
3936
3937 AlterTypeOwner_oid(typeOid, newOwnerId, true);
3938 }
3939
3940 ObjectAddressSet(address, TypeRelationId, typeOid);
3941
3942 /* Clean up */
3944
3945 return address;
3946}
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5341
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2652
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3834
Oid get_multirange_range(Oid multirangeOid)
Definition: lsyscache.c:3650
Type LookupTypeName(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, bool missing_ok)
Definition: parse_type.c:38
@ OBJECT_SCHEMA
Definition: parsenodes.h:2361
#define ACL_CREATE
Definition: parsenodes.h:85
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition: typecmds.c:3960

References ACL_CREATE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTypeOwner_oid(), check_can_set_role(), ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), get_multirange_range(), get_namespace_name(), get_rel_relkind(), GETSTRUCT(), GetUserId(), heap_copytuple(), LookupTypeName(), makeTypeNameFromNameList(), object_aclcheck(), OBJECT_DOMAIN, object_ownercheck(), OBJECT_SCHEMA, ObjectAddressSet, OidIsValid, ReleaseSysCache(), RowExclusiveLock, superuser(), table_close(), table_open(), TypeNameToString(), and typeTypeId().

Referenced by ExecAlterOwnerStmt().

◆ AlterTypeOwner_oid()

void AlterTypeOwner_oid ( Oid  typeOid,
Oid  newOwnerId,
bool  hasDependEntry 
)

Definition at line 3960 of file typecmds.c.

3961{
3962 Relation rel;
3963 HeapTuple tup;
3964 Form_pg_type typTup;
3965
3966 rel = table_open(TypeRelationId, RowExclusiveLock);
3967
3968 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3969 if (!HeapTupleIsValid(tup))
3970 elog(ERROR, "cache lookup failed for type %u", typeOid);
3971 typTup = (Form_pg_type) GETSTRUCT(tup);
3972
3973 /*
3974 * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3975 * the pg_class entry properly. That will call back to
3976 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3977 */
3978 if (typTup->typtype == TYPTYPE_COMPOSITE)
3979 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3980 else
3981 AlterTypeOwnerInternal(typeOid, newOwnerId);
3982
3983 /* Update owner dependency reference */
3984 if (hasDependEntry)
3985 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3986
3987 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3988
3989 ReleaseSysCache(tup);
3991}
#define AccessExclusiveLock
Definition: lockdefs.h:43
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:316
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:16064
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:4000

References AccessExclusiveLock, AlterTypeOwnerInternal(), ATExecChangeOwner(), changeDependencyOnOwner(), elog, ERROR, GETSTRUCT(), HeapTupleIsValid, InvokeObjectPostAlterHook, ObjectIdGetDatum(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), table_close(), and table_open().

Referenced by AlterTypeOwner(), and shdepReassignOwned_Owner().

◆ AlterTypeOwnerInternal()

void AlterTypeOwnerInternal ( Oid  typeOid,
Oid  newOwnerId 
)

Definition at line 4000 of file typecmds.c.

4001{
4002 Relation rel;
4003 HeapTuple tup;
4004 Form_pg_type typTup;
4005 Datum repl_val[Natts_pg_type];
4006 bool repl_null[Natts_pg_type];
4007 bool repl_repl[Natts_pg_type];
4008 Acl *newAcl;
4009 Datum aclDatum;
4010 bool isNull;
4011
4012 rel = table_open(TypeRelationId, RowExclusiveLock);
4013
4014 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
4015 if (!HeapTupleIsValid(tup))
4016 elog(ERROR, "cache lookup failed for type %u", typeOid);
4017 typTup = (Form_pg_type) GETSTRUCT(tup);
4018
4019 memset(repl_null, false, sizeof(repl_null));
4020 memset(repl_repl, false, sizeof(repl_repl));
4021
4022 repl_repl[Anum_pg_type_typowner - 1] = true;
4023 repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
4024
4025 aclDatum = heap_getattr(tup,
4026 Anum_pg_type_typacl,
4027 RelationGetDescr(rel),
4028 &isNull);
4029 /* Null ACLs do not require changes */
4030 if (!isNull)
4031 {
4032 newAcl = aclnewowner(DatumGetAclP(aclDatum),
4033 typTup->typowner, newOwnerId);
4034 repl_repl[Anum_pg_type_typacl - 1] = true;
4035 repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
4036 }
4037
4038 tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
4039 repl_repl);
4040
4041 CatalogTupleUpdate(rel, &tup->t_self, tup);
4042
4043 /* If it has an array type, update that too */
4044 if (OidIsValid(typTup->typarray))
4045 AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
4046
4047 /* If it is a range type, update the associated multirange too */
4048 if (typTup->typtype == TYPTYPE_RANGE)
4049 {
4050 Oid multirange_typeid = get_range_multirange(typeOid);
4051
4052 if (!OidIsValid(multirange_typeid))
4053 ereport(ERROR,
4054 (errcode(ERRCODE_UNDEFINED_OBJECT),
4055 errmsg("could not find multirange type for data type %s",
4056 format_type_be(typeOid))));
4057 AlterTypeOwnerInternal(multirange_typeid, newOwnerId);
4058 }
4059
4060 /* Clean up */
4062}
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1119
#define DatumGetAclP(X)
Definition: acl.h:120
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:904
Oid get_range_multirange(Oid rangeOid)
Definition: lsyscache.c:3625
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332

References aclnewowner(), AlterTypeOwnerInternal(), CatalogTupleUpdate(), DatumGetAclP, elog, ereport, errcode(), errmsg(), ERROR, format_type_be(), get_range_multirange(), GETSTRUCT(), heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, ObjectIdGetDatum(), OidIsValid, PointerGetDatum(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by AlterTypeOwner_oid(), AlterTypeOwnerInternal(), and ATExecChangeOwner().

◆ AssignTypeArrayOid()

Oid AssignTypeArrayOid ( void  )

Definition at line 2451 of file typecmds.c.

2452{
2453 Oid type_array_oid;
2454
2455 /* Use binary-upgrade override for pg_type.typarray? */
2456 if (IsBinaryUpgrade)
2457 {
2459 ereport(ERROR,
2460 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2461 errmsg("pg_type array OID value not set when in binary upgrade mode")));
2462
2465 }
2466 else
2467 {
2468 Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2469
2470 type_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2471 Anum_pg_type_oid);
2472 table_close(pg_type, AccessShareLock);
2473 }
2474
2475 return type_array_oid;
2476}
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:448
bool IsBinaryUpgrade
Definition: globals.c:121
Oid binary_upgrade_next_array_pg_type_oid
Definition: typecmds.c:109

References AccessShareLock, binary_upgrade_next_array_pg_type_oid, ereport, errcode(), errmsg(), ERROR, GetNewOidWithIndex(), InvalidOid, IsBinaryUpgrade, OidIsValid, table_close(), and table_open().

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

◆ AssignTypeMultirangeArrayOid()

Oid AssignTypeMultirangeArrayOid ( void  )

Definition at line 2517 of file typecmds.c.

2518{
2519 Oid type_multirange_array_oid;
2520
2521 /* Use binary-upgrade override for pg_type.oid? */
2522 if (IsBinaryUpgrade)
2523 {
2525 ereport(ERROR,
2526 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2527 errmsg("pg_type multirange array OID value not set when in binary upgrade mode")));
2528
2529 type_multirange_array_oid = binary_upgrade_next_mrng_array_pg_type_oid;
2531 }
2532 else
2533 {
2534 Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2535
2536 type_multirange_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2537 Anum_pg_type_oid);
2538 table_close(pg_type, AccessShareLock);
2539 }
2540
2541 return type_multirange_array_oid;
2542}
Oid binary_upgrade_next_mrng_array_pg_type_oid
Definition: typecmds.c:111

References AccessShareLock, binary_upgrade_next_mrng_array_pg_type_oid, ereport, errcode(), errmsg(), ERROR, GetNewOidWithIndex(), InvalidOid, IsBinaryUpgrade, OidIsValid, table_close(), and table_open().

Referenced by DefineRange().

◆ AssignTypeMultirangeOid()

Oid AssignTypeMultirangeOid ( void  )

Definition at line 2484 of file typecmds.c.

2485{
2486 Oid type_multirange_oid;
2487
2488 /* Use binary-upgrade override for pg_type.oid? */
2489 if (IsBinaryUpgrade)
2490 {
2492 ereport(ERROR,
2493 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2494 errmsg("pg_type multirange OID value not set when in binary upgrade mode")));
2495
2496 type_multirange_oid = binary_upgrade_next_mrng_pg_type_oid;
2498 }
2499 else
2500 {
2501 Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2502
2503 type_multirange_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2504 Anum_pg_type_oid);
2505 table_close(pg_type, AccessShareLock);
2506 }
2507
2508 return type_multirange_oid;
2509}
Oid binary_upgrade_next_mrng_pg_type_oid
Definition: typecmds.c:110

References AccessShareLock, binary_upgrade_next_mrng_pg_type_oid, ereport, errcode(), errmsg(), ERROR, GetNewOidWithIndex(), InvalidOid, IsBinaryUpgrade, OidIsValid, table_close(), and table_open().

Referenced by DefineRange().

◆ checkDomainOwner()

void checkDomainOwner ( HeapTuple  tup)

Definition at line 3499 of file typecmds.c.

3500{
3501 Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
3502
3503 /* Check that this is actually a domain */
3504 if (typTup->typtype != TYPTYPE_DOMAIN)
3505 ereport(ERROR,
3506 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3507 errmsg("%s is not a domain",
3508 format_type_be(typTup->oid))));
3509
3510 /* Permission check: must own type */
3511 if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
3513}

References aclcheck_error_type(), ACLCHECK_NOT_OWNER, ereport, errcode(), errmsg(), ERROR, format_type_be(), GETSTRUCT(), GetUserId(), and object_ownercheck().

Referenced by AlterDomainAddConstraint(), AlterDomainDefault(), AlterDomainDropConstraint(), AlterDomainNotNull(), AlterDomainValidateConstraint(), and RenameConstraint().

◆ DefineCompositeType()

ObjectAddress DefineCompositeType ( RangeVar typevar,
List coldeflist 
)

Definition at line 2559 of file typecmds.c.

2560{
2561 CreateStmt *createStmt = makeNode(CreateStmt);
2562 Oid old_type_oid;
2563 Oid typeNamespace;
2564 ObjectAddress address;
2565
2566 /*
2567 * now set the parameters for keys/inheritance etc. All of these are
2568 * uninteresting for composite types...
2569 */
2570 createStmt->relation = typevar;
2571 createStmt->tableElts = coldeflist;
2572 createStmt->inhRelations = NIL;
2573 createStmt->constraints = NIL;
2574 createStmt->options = NIL;
2575 createStmt->oncommit = ONCOMMIT_NOOP;
2576 createStmt->tablespacename = NULL;
2577 createStmt->if_not_exists = false;
2578
2579 /*
2580 * Check for collision with an existing type name. If there is one and
2581 * it's an autogenerated array, we can rename it out of the way. This
2582 * check is here mainly to get a better error message about a "type"
2583 * instead of below about a "relation".
2584 */
2585 typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2586 NoLock, NULL);
2587 RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2588 old_type_oid =
2589 GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
2590 CStringGetDatum(createStmt->relation->relname),
2591 ObjectIdGetDatum(typeNamespace));
2592 if (OidIsValid(old_type_oid))
2593 {
2594 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2595 ereport(ERROR,
2597 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2598 }
2599
2600 /*
2601 * Finally create the relation. This also creates the type.
2602 */
2603 DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2604 NULL);
2605
2606 return address;
2607}
#define NoLock
Definition: lockdefs.h:34
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:738
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition: namespace.c:845
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:903
@ ONCOMMIT_NOOP
Definition: primnodes.h:58
List * tableElts
Definition: parsenodes.h:2751
OnCommitAction oncommit
Definition: parsenodes.h:2760
List * options
Definition: parsenodes.h:2759
bool if_not_exists
Definition: parsenodes.h:2763
List * inhRelations
Definition: parsenodes.h:2752
RangeVar * relation
Definition: parsenodes.h:2750
char * tablespacename
Definition: parsenodes.h:2761
List * constraints
Definition: parsenodes.h:2757
char * relname
Definition: primnodes.h:83
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:111
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:764

References CreateStmt::constraints, CStringGetDatum(), DefineRelation(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, GetSysCacheOid2, CreateStmt::if_not_exists, CreateStmt::inhRelations, InvalidOid, makeNode, moveArrayTypeName(), NIL, NoLock, ObjectIdGetDatum(), OidIsValid, CreateStmt::oncommit, ONCOMMIT_NOOP, CreateStmt::options, RangeVarAdjustRelationPersistence(), RangeVarGetAndCheckCreationNamespace(), CreateStmt::relation, RangeVar::relname, CreateStmt::tableElts, and CreateStmt::tablespacename.

Referenced by ProcessUtilitySlow().

◆ DefineDomain()

ObjectAddress DefineDomain ( ParseState pstate,
CreateDomainStmt stmt 
)

Definition at line 697 of file typecmds.c.

698{
699 char *domainName;
700 char *domainArrayName;
701 Oid domainNamespace;
702 AclResult aclresult;
703 int16 internalLength;
704 Oid inputProcedure;
705 Oid outputProcedure;
706 Oid receiveProcedure;
707 Oid sendProcedure;
708 Oid analyzeProcedure;
709 bool byValue;
710 char category;
711 char delimiter;
712 char alignment;
713 char storage;
714 char typtype;
715 Datum datum;
716 bool isnull;
717 char *defaultValue = NULL;
718 char *defaultValueBin = NULL;
719 bool saw_default = false;
720 bool typNotNull = false;
721 bool nullDefined = false;
722 int32 typNDims = list_length(stmt->typeName->arrayBounds);
723 HeapTuple typeTup;
724 List *schema = stmt->constraints;
725 ListCell *listptr;
726 Oid basetypeoid;
727 Oid old_type_oid;
728 Oid domaincoll;
729 Oid domainArrayOid;
730 Form_pg_type baseType;
731 int32 basetypeMod;
732 Oid baseColl;
733 ObjectAddress address;
734
735 /* Convert list of names to a name and namespace */
736 domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
737 &domainName);
738
739 /* Check we have creation rights in target namespace */
740 aclresult = object_aclcheck(NamespaceRelationId, domainNamespace, GetUserId(),
741 ACL_CREATE);
742 if (aclresult != ACLCHECK_OK)
743 aclcheck_error(aclresult, OBJECT_SCHEMA,
744 get_namespace_name(domainNamespace));
745
746 /*
747 * Check for collision with an existing type name. If there is one and
748 * it's an autogenerated array, we can rename it out of the way.
749 */
750 old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
751 CStringGetDatum(domainName),
752 ObjectIdGetDatum(domainNamespace));
753 if (OidIsValid(old_type_oid))
754 {
755 if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
758 errmsg("type \"%s\" already exists", domainName)));
759 }
760
761 /*
762 * Look up the base type.
763 */
764 typeTup = typenameType(pstate, stmt->typeName, &basetypeMod);
765 baseType = (Form_pg_type) GETSTRUCT(typeTup);
766 basetypeoid = baseType->oid;
767
768 /*
769 * Base type must be a plain base type, a composite type, another domain,
770 * an enum or a range type. Domains over pseudotypes would create a
771 * security hole. (It would be shorter to code this to just check for
772 * pseudotypes; but it seems safer to call out the specific typtypes that
773 * are supported, rather than assume that all future typtypes would be
774 * automatically supported.)
775 */
776 typtype = baseType->typtype;
777 if (typtype != TYPTYPE_BASE &&
778 typtype != TYPTYPE_COMPOSITE &&
779 typtype != TYPTYPE_DOMAIN &&
780 typtype != TYPTYPE_ENUM &&
781 typtype != TYPTYPE_RANGE &&
782 typtype != TYPTYPE_MULTIRANGE)
784 (errcode(ERRCODE_DATATYPE_MISMATCH),
785 errmsg("\"%s\" is not a valid base type for a domain",
786 TypeNameToString(stmt->typeName)),
787 parser_errposition(pstate, stmt->typeName->location)));
788
789 aclresult = object_aclcheck(TypeRelationId, basetypeoid, GetUserId(), ACL_USAGE);
790 if (aclresult != ACLCHECK_OK)
791 aclcheck_error_type(aclresult, basetypeoid);
792
793 /*
794 * Collect the properties of the new domain. Some are inherited from the
795 * base type, some are not. If you change any of this inheritance
796 * behavior, be sure to update AlterTypeRecurse() to match!
797 */
798
799 /*
800 * Identify the collation if any
801 */
802 baseColl = baseType->typcollation;
803 if (stmt->collClause)
804 domaincoll = get_collation_oid(stmt->collClause->collname, false);
805 else
806 domaincoll = baseColl;
807
808 /* Complain if COLLATE is applied to an uncollatable type */
809 if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
811 (errcode(ERRCODE_DATATYPE_MISMATCH),
812 errmsg("collations are not supported by type %s",
813 format_type_be(basetypeoid)),
814 parser_errposition(pstate, stmt->typeName->location)));
815
816 /* passed by value */
817 byValue = baseType->typbyval;
818
819 /* Required Alignment */
820 alignment = baseType->typalign;
821
822 /* TOAST Strategy */
823 storage = baseType->typstorage;
824
825 /* Storage Length */
826 internalLength = baseType->typlen;
827
828 /* Type Category */
829 category = baseType->typcategory;
830
831 /* Array element Delimiter */
832 delimiter = baseType->typdelim;
833
834 /* I/O Functions */
835 inputProcedure = F_DOMAIN_IN;
836 outputProcedure = baseType->typoutput;
837 receiveProcedure = F_DOMAIN_RECV;
838 sendProcedure = baseType->typsend;
839
840 /* Domains never accept typmods, so no typmodin/typmodout needed */
841
842 /* Analysis function */
843 analyzeProcedure = baseType->typanalyze;
844
845 /*
846 * Domains don't need a subscript function, since they are not
847 * subscriptable on their own. If the base type is subscriptable, the
848 * parser will reduce the type to the base type before subscripting.
849 */
850
851 /* Inherited default value */
852 datum = SysCacheGetAttr(TYPEOID, typeTup,
853 Anum_pg_type_typdefault, &isnull);
854 if (!isnull)
855 defaultValue = TextDatumGetCString(datum);
856
857 /* Inherited default binary value */
858 datum = SysCacheGetAttr(TYPEOID, typeTup,
859 Anum_pg_type_typdefaultbin, &isnull);
860 if (!isnull)
861 defaultValueBin = TextDatumGetCString(datum);
862
863 /*
864 * Run through constraints manually to avoid the additional processing
865 * conducted by DefineRelation() and friends.
866 */
867 foreach(listptr, schema)
868 {
869 Constraint *constr = lfirst(listptr);
870
871 if (!IsA(constr, Constraint))
872 elog(ERROR, "unrecognized node type: %d",
873 (int) nodeTag(constr));
874 switch (constr->contype)
875 {
876 case CONSTR_DEFAULT:
877
878 /*
879 * The inherited default value may be overridden by the user
880 * with the DEFAULT <expr> clause ... but only once.
881 */
882 if (saw_default)
884 errcode(ERRCODE_SYNTAX_ERROR),
885 errmsg("multiple default expressions"),
886 parser_errposition(pstate, constr->location));
887 saw_default = true;
888
889 if (constr->raw_expr)
890 {
891 Node *defaultExpr;
892
893 /*
894 * Cook the constr->raw_expr into an expression. Note:
895 * name is strictly for error message
896 */
897 defaultExpr = cookDefault(pstate, constr->raw_expr,
898 basetypeoid,
899 basetypeMod,
900 domainName,
901 0);
902
903 /*
904 * If the expression is just a NULL constant, we treat it
905 * like not having a default.
906 *
907 * Note that if the basetype is another domain, we'll see
908 * a CoerceToDomain expr here and not discard the default.
909 * This is critical because the domain default needs to be
910 * retained to override any default that the base domain
911 * might have.
912 */
913 if (defaultExpr == NULL ||
914 (IsA(defaultExpr, Const) &&
915 ((Const *) defaultExpr)->constisnull))
916 {
917 defaultValue = NULL;
918 defaultValueBin = NULL;
919 }
920 else
921 {
922 /*
923 * Expression must be stored as a nodeToString result,
924 * but we also require a valid textual representation
925 * (mainly to make life easier for pg_dump).
926 */
927 defaultValue =
928 deparse_expression(defaultExpr,
929 NIL, false, false);
930 defaultValueBin = nodeToString(defaultExpr);
931 }
932 }
933 else
934 {
935 /* No default (can this still happen?) */
936 defaultValue = NULL;
937 defaultValueBin = NULL;
938 }
939 break;
940
941 case CONSTR_NOTNULL:
942 if (nullDefined)
943 {
944 if (!typNotNull)
946 errcode(ERRCODE_SYNTAX_ERROR),
947 errmsg("conflicting NULL/NOT NULL constraints"),
948 parser_errposition(pstate, constr->location));
949
951 errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
952 errmsg("redundant NOT NULL constraint definition"),
953 parser_errposition(pstate, constr->location));
954 }
955 if (constr->is_no_inherit)
957 errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
958 errmsg("not-null constraints for domains cannot be marked NO INHERIT"),
959 parser_errposition(pstate, constr->location));
960 typNotNull = true;
961 nullDefined = true;
962 break;
963
964 case CONSTR_NULL:
965 if (nullDefined && typNotNull)
967 errcode(ERRCODE_SYNTAX_ERROR),
968 errmsg("conflicting NULL/NOT NULL constraints"),
969 parser_errposition(pstate, constr->location));
970 typNotNull = false;
971 nullDefined = true;
972 break;
973
974 case CONSTR_CHECK:
975
976 /*
977 * Check constraints are handled after domain creation, as
978 * they require the Oid of the domain; at this point we can
979 * only check that they're not marked NO INHERIT, because that
980 * would be bogus.
981 */
982 if (constr->is_no_inherit)
984 errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
985 errmsg("check constraints for domains cannot be marked NO INHERIT"),
986 parser_errposition(pstate, constr->location));
987
988 break;
989
990 /*
991 * All else are error cases
992 */
993 case CONSTR_UNIQUE:
995 errcode(ERRCODE_SYNTAX_ERROR),
996 errmsg("unique constraints not possible for domains"),
997 parser_errposition(pstate, constr->location));
998 break;
999
1000 case CONSTR_PRIMARY:
1001 ereport(ERROR,
1002 (errcode(ERRCODE_SYNTAX_ERROR),
1003 errmsg("primary key constraints not possible for domains"),
1004 parser_errposition(pstate, constr->location)));
1005 break;
1006
1007 case CONSTR_EXCLUSION:
1008 ereport(ERROR,
1009 (errcode(ERRCODE_SYNTAX_ERROR),
1010 errmsg("exclusion constraints not possible for domains"),
1011 parser_errposition(pstate, constr->location)));
1012 break;
1013
1014 case CONSTR_FOREIGN:
1015 ereport(ERROR,
1016 (errcode(ERRCODE_SYNTAX_ERROR),
1017 errmsg("foreign key constraints not possible for domains"),
1018 parser_errposition(pstate, constr->location)));
1019 break;
1020
1025 ereport(ERROR,
1026 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1027 errmsg("specifying constraint deferrability not supported for domains"),
1028 parser_errposition(pstate, constr->location)));
1029 break;
1030
1031 case CONSTR_GENERATED:
1032 case CONSTR_IDENTITY:
1033 ereport(ERROR,
1034 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1035 errmsg("specifying GENERATED not supported for domains"),
1036 parser_errposition(pstate, constr->location)));
1037 break;
1038
1041 ereport(ERROR,
1042 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1043 errmsg("specifying constraint enforceability not supported for domains"),
1044 parser_errposition(pstate, constr->location)));
1045 break;
1046
1047 /* no default, to let compiler warn about missing case */
1048 }
1049 }
1050
1051 /* Allocate OID for array type */
1052 domainArrayOid = AssignTypeArrayOid();
1053
1054 /*
1055 * Have TypeCreate do all the real work.
1056 */
1057 address =
1058 TypeCreate(InvalidOid, /* no predetermined type OID */
1059 domainName, /* type name */
1060 domainNamespace, /* namespace */
1061 InvalidOid, /* relation oid (n/a here) */
1062 0, /* relation kind (ditto) */
1063 GetUserId(), /* owner's ID */
1064 internalLength, /* internal size */
1065 TYPTYPE_DOMAIN, /* type-type (domain type) */
1066 category, /* type-category */
1067 false, /* domain types are never preferred */
1068 delimiter, /* array element delimiter */
1069 inputProcedure, /* input procedure */
1070 outputProcedure, /* output procedure */
1071 receiveProcedure, /* receive procedure */
1072 sendProcedure, /* send procedure */
1073 InvalidOid, /* typmodin procedure - none */
1074 InvalidOid, /* typmodout procedure - none */
1075 analyzeProcedure, /* analyze procedure */
1076 InvalidOid, /* subscript procedure - none */
1077 InvalidOid, /* no array element type */
1078 false, /* this isn't an array */
1079 domainArrayOid, /* array type we are about to create */
1080 basetypeoid, /* base type ID */
1081 defaultValue, /* default type value (text) */
1082 defaultValueBin, /* default type value (binary) */
1083 byValue, /* passed by value */
1084 alignment, /* required alignment */
1085 storage, /* TOAST strategy */
1086 basetypeMod, /* typeMod value */
1087 typNDims, /* Array dimensions for base type */
1088 typNotNull, /* Type NOT NULL */
1089 domaincoll); /* type's collation */
1090
1091 /*
1092 * Create the array type that goes with it.
1093 */
1094 domainArrayName = makeArrayTypeName(domainName, domainNamespace);
1095
1096 /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for arrays */
1097 alignment = (alignment == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
1098
1099 TypeCreate(domainArrayOid, /* force assignment of this type OID */
1100 domainArrayName, /* type name */
1101 domainNamespace, /* namespace */
1102 InvalidOid, /* relation oid (n/a here) */
1103 0, /* relation kind (ditto) */
1104 GetUserId(), /* owner's ID */
1105 -1, /* internal size (always varlena) */
1106 TYPTYPE_BASE, /* type-type (base type) */
1107 TYPCATEGORY_ARRAY, /* type-category (array) */
1108 false, /* array types are never preferred */
1109 delimiter, /* array element delimiter */
1110 F_ARRAY_IN, /* input procedure */
1111 F_ARRAY_OUT, /* output procedure */
1112 F_ARRAY_RECV, /* receive procedure */
1113 F_ARRAY_SEND, /* send procedure */
1114 InvalidOid, /* typmodin procedure - none */
1115 InvalidOid, /* typmodout procedure - none */
1116 F_ARRAY_TYPANALYZE, /* analyze procedure */
1117 F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1118 address.objectId, /* element type ID */
1119 true, /* yes this is an array type */
1120 InvalidOid, /* no further array type */
1121 InvalidOid, /* base type ID */
1122 NULL, /* never a default type value */
1123 NULL, /* binary default isn't sent either */
1124 false, /* never passed by value */
1125 alignment, /* see above */
1126 TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
1127 -1, /* typMod (Domains only) */
1128 0, /* Array dimensions of typbasetype */
1129 false, /* Type NOT NULL */
1130 domaincoll); /* type's collation */
1131
1132 pfree(domainArrayName);
1133
1134 /*
1135 * Process constraints which refer to the domain ID returned by TypeCreate
1136 */
1137 foreach(listptr, schema)
1138 {
1139 Constraint *constr = lfirst(listptr);
1140
1141 /* it must be a Constraint, per check above */
1142
1143 switch (constr->contype)
1144 {
1145 case CONSTR_CHECK:
1146 domainAddCheckConstraint(address.objectId, domainNamespace,
1147 basetypeoid, basetypeMod,
1148 constr, domainName, NULL);
1149 break;
1150
1151 case CONSTR_NOTNULL:
1152 domainAddNotNullConstraint(address.objectId, domainNamespace,
1153 basetypeoid, basetypeMod,
1154 constr, domainName, NULL);
1155 break;
1156
1157 /* Other constraint types were fully processed above */
1158
1159 default:
1160 break;
1161 }
1162
1163 /* CCI so we can detect duplicate constraint names */
1165 }
1166
1167 /*
1168 * Now we can clean up.
1169 */
1170 ReleaseSysCache(typeTup);
1171
1172 return address;
1173}
int16_t int16
Definition: c.h:536
int32_t int32
Definition: c.h:537
#define storage
Definition: indent_codes.h:68
void pfree(void *pointer)
Definition: mcxt.c:1594
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition: namespace.c:3557
Oid get_collation_oid(List *collname, bool missing_ok)
Definition: namespace.c:4041
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
#define ACL_USAGE
Definition: parsenodes.h:84
@ CONSTR_ATTR_ENFORCED
Definition: parsenodes.h:2814
@ CONSTR_FOREIGN
Definition: parsenodes.h:2809
@ CONSTR_ATTR_DEFERRED
Definition: parsenodes.h:2812
@ CONSTR_IDENTITY
Definition: parsenodes.h:2803
@ CONSTR_UNIQUE
Definition: parsenodes.h:2807
@ CONSTR_ATTR_NOT_DEFERRABLE
Definition: parsenodes.h:2811
@ CONSTR_DEFAULT
Definition: parsenodes.h:2802
@ CONSTR_ATTR_IMMEDIATE
Definition: parsenodes.h:2813
@ CONSTR_NULL
Definition: parsenodes.h:2799
@ CONSTR_GENERATED
Definition: parsenodes.h:2804
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2808
@ CONSTR_ATTR_DEFERRABLE
Definition: parsenodes.h:2810
@ CONSTR_ATTR_NOT_ENFORCED
Definition: parsenodes.h:2815
@ CONSTR_PRIMARY
Definition: parsenodes.h:2806
static int list_length(const List *l)
Definition: pg_list.h:152
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: pg_type.c:195
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:838
bool is_no_inherit
Definition: parsenodes.h:2840
Node * raw_expr
Definition: parsenodes.h:2841
Definition: pg_list.h:54
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:595
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2451
void CommandCounterIncrement(void)
Definition: xact.c:1101

References ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, AssignTypeArrayOid(), CommandCounterIncrement(), CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_ENFORCED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_ATTR_NOT_ENFORCED, CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_GENERATED, CONSTR_IDENTITY, CONSTR_NOTNULL, CONSTR_NULL, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, cookDefault(), CStringGetDatum(), deparse_expression(), domainAddCheckConstraint(), domainAddNotNullConstraint(), elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, format_type_be(), get_collation_oid(), get_namespace_name(), GETSTRUCT(), GetSysCacheOid2, GetUserId(), InvalidOid, Constraint::is_no_inherit, IsA, lfirst, list_length(), Constraint::location, makeArrayTypeName(), moveArrayTypeName(), NIL, nodeTag, nodeToString(), object_aclcheck(), OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, parser_errposition(), pfree(), QualifiedNameGetCreationNamespace(), Constraint::raw_expr, ReleaseSysCache(), stmt, storage, SysCacheGetAttr(), TextDatumGetCString, TypeCreate(), TypeNameToString(), and typenameType().

Referenced by ProcessUtilitySlow().

◆ DefineEnum()

ObjectAddress DefineEnum ( CreateEnumStmt stmt)

Definition at line 1181 of file typecmds.c.

1182{
1183 char *enumName;
1184 char *enumArrayName;
1185 Oid enumNamespace;
1186 AclResult aclresult;
1187 Oid old_type_oid;
1188 Oid enumArrayOid;
1189 ObjectAddress enumTypeAddr;
1190
1191 /* Convert list of names to a name and namespace */
1192 enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1193 &enumName);
1194
1195 /* Check we have creation rights in target namespace */
1196 aclresult = object_aclcheck(NamespaceRelationId, enumNamespace, GetUserId(), ACL_CREATE);
1197 if (aclresult != ACLCHECK_OK)
1198 aclcheck_error(aclresult, OBJECT_SCHEMA,
1199 get_namespace_name(enumNamespace));
1200
1201 /*
1202 * Check for collision with an existing type name. If there is one and
1203 * it's an autogenerated array, we can rename it out of the way.
1204 */
1205 old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
1206 CStringGetDatum(enumName),
1207 ObjectIdGetDatum(enumNamespace));
1208 if (OidIsValid(old_type_oid))
1209 {
1210 if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1211 ereport(ERROR,
1213 errmsg("type \"%s\" already exists", enumName)));
1214 }
1215
1216 /* Allocate OID for array type */
1217 enumArrayOid = AssignTypeArrayOid();
1218
1219 /* Create the pg_type entry */
1220 enumTypeAddr =
1221 TypeCreate(InvalidOid, /* no predetermined type OID */
1222 enumName, /* type name */
1223 enumNamespace, /* namespace */
1224 InvalidOid, /* relation oid (n/a here) */
1225 0, /* relation kind (ditto) */
1226 GetUserId(), /* owner's ID */
1227 sizeof(Oid), /* internal size */
1228 TYPTYPE_ENUM, /* type-type (enum type) */
1229 TYPCATEGORY_ENUM, /* type-category (enum type) */
1230 false, /* enum types are never preferred */
1231 DEFAULT_TYPDELIM, /* array element delimiter */
1232 F_ENUM_IN, /* input procedure */
1233 F_ENUM_OUT, /* output procedure */
1234 F_ENUM_RECV, /* receive procedure */
1235 F_ENUM_SEND, /* send procedure */
1236 InvalidOid, /* typmodin procedure - none */
1237 InvalidOid, /* typmodout procedure - none */
1238 InvalidOid, /* analyze procedure - default */
1239 InvalidOid, /* subscript procedure - none */
1240 InvalidOid, /* element type ID */
1241 false, /* this is not an array type */
1242 enumArrayOid, /* array type we are about to create */
1243 InvalidOid, /* base type ID (only for domains) */
1244 NULL, /* never a default type value */
1245 NULL, /* binary default isn't sent either */
1246 true, /* always passed by value */
1247 TYPALIGN_INT, /* int alignment */
1248 TYPSTORAGE_PLAIN, /* TOAST strategy always plain */
1249 -1, /* typMod (Domains only) */
1250 0, /* Array dimensions of typbasetype */
1251 false, /* Type NOT NULL */
1252 InvalidOid); /* type's collation */
1253
1254 /* Enter the enum's values into pg_enum */
1255 EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
1256
1257 /*
1258 * Create the array type that goes with it.
1259 */
1260 enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1261
1262 TypeCreate(enumArrayOid, /* force assignment of this type OID */
1263 enumArrayName, /* type name */
1264 enumNamespace, /* namespace */
1265 InvalidOid, /* relation oid (n/a here) */
1266 0, /* relation kind (ditto) */
1267 GetUserId(), /* owner's ID */
1268 -1, /* internal size (always varlena) */
1269 TYPTYPE_BASE, /* type-type (base type) */
1270 TYPCATEGORY_ARRAY, /* type-category (array) */
1271 false, /* array types are never preferred */
1272 DEFAULT_TYPDELIM, /* array element delimiter */
1273 F_ARRAY_IN, /* input procedure */
1274 F_ARRAY_OUT, /* output procedure */
1275 F_ARRAY_RECV, /* receive procedure */
1276 F_ARRAY_SEND, /* send procedure */
1277 InvalidOid, /* typmodin procedure - none */
1278 InvalidOid, /* typmodout procedure - none */
1279 F_ARRAY_TYPANALYZE, /* analyze procedure */
1280 F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1281 enumTypeAddr.objectId, /* element type ID */
1282 true, /* yes this is an array type */
1283 InvalidOid, /* no further array type */
1284 InvalidOid, /* base type ID */
1285 NULL, /* never a default type value */
1286 NULL, /* binary default isn't sent either */
1287 false, /* never passed by value */
1288 TYPALIGN_INT, /* enums have int align, so do their arrays */
1289 TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
1290 -1, /* typMod (Domains only) */
1291 0, /* Array dimensions of typbasetype */
1292 false, /* Type NOT NULL */
1293 InvalidOid); /* type's collation */
1294
1295 pfree(enumArrayName);
1296
1297 return enumTypeAddr;
1298}
void EnumValuesCreate(Oid enumTypeOid, List *vals)
Definition: pg_enum.c:84
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, AssignTypeArrayOid(), CStringGetDatum(), DEFAULT_TYPDELIM, EnumValuesCreate(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, get_namespace_name(), GetSysCacheOid2, GetUserId(), InvalidOid, makeArrayTypeName(), moveArrayTypeName(), object_aclcheck(), OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, pfree(), QualifiedNameGetCreationNamespace(), stmt, and TypeCreate().

Referenced by ProcessUtilitySlow().

◆ DefineRange()

ObjectAddress DefineRange ( ParseState pstate,
CreateRangeStmt stmt 
)

Definition at line 1380 of file typecmds.c.

1381{
1382 char *typeName;
1383 Oid typeNamespace;
1384 Oid typoid;
1385 char *rangeArrayName;
1386 char *multirangeTypeName = NULL;
1387 char *multirangeArrayName;
1388 Oid multirangeNamespace = InvalidOid;
1389 Oid rangeArrayOid;
1390 Oid multirangeOid;
1391 Oid multirangeArrayOid;
1392 Oid rangeSubtype = InvalidOid;
1393 List *rangeSubOpclassName = NIL;
1394 List *rangeCollationName = NIL;
1395 List *rangeCanonicalName = NIL;
1396 List *rangeSubtypeDiffName = NIL;
1397 Oid rangeSubOpclass;
1398 Oid rangeCollation;
1399 regproc rangeCanonical;
1400 regproc rangeSubtypeDiff;
1401 int16 subtyplen;
1402 bool subtypbyval;
1403 char subtypalign;
1404 char alignment;
1405 AclResult aclresult;
1406 ListCell *lc;
1407 ObjectAddress address;
1409 Oid castFuncOid;
1410
1411 /* Convert list of names to a name and namespace */
1412 typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1413 &typeName);
1414
1415 /* Check we have creation rights in target namespace */
1416 aclresult = object_aclcheck(NamespaceRelationId, typeNamespace, GetUserId(), ACL_CREATE);
1417 if (aclresult != ACLCHECK_OK)
1418 aclcheck_error(aclresult, OBJECT_SCHEMA,
1419 get_namespace_name(typeNamespace));
1420
1421 /*
1422 * Look to see if type already exists.
1423 */
1424 typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
1425 CStringGetDatum(typeName),
1426 ObjectIdGetDatum(typeNamespace));
1427
1428 /*
1429 * If it's not a shell, see if it's an autogenerated array type, and if so
1430 * rename it out of the way.
1431 */
1432 if (OidIsValid(typoid) && get_typisdefined(typoid))
1433 {
1434 if (moveArrayTypeName(typoid, typeName, typeNamespace))
1435 typoid = InvalidOid;
1436 else
1437 ereport(ERROR,
1439 errmsg("type \"%s\" already exists", typeName)));
1440 }
1441
1442 /*
1443 * Unlike DefineType(), we don't insist on a shell type existing first, as
1444 * it's only needed if the user wants to specify a canonical function.
1445 */
1446
1447 /* Extract the parameters from the parameter list */
1448 foreach(lc, stmt->params)
1449 {
1450 DefElem *defel = (DefElem *) lfirst(lc);
1451
1452 if (strcmp(defel->defname, "subtype") == 0)
1453 {
1454 if (OidIsValid(rangeSubtype))
1455 errorConflictingDefElem(defel, pstate);
1456 /* we can look up the subtype name immediately */
1457 rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1458 }
1459 else if (strcmp(defel->defname, "subtype_opclass") == 0)
1460 {
1461 if (rangeSubOpclassName != NIL)
1462 errorConflictingDefElem(defel, pstate);
1463 rangeSubOpclassName = defGetQualifiedName(defel);
1464 }
1465 else if (strcmp(defel->defname, "collation") == 0)
1466 {
1467 if (rangeCollationName != NIL)
1468 errorConflictingDefElem(defel, pstate);
1469 rangeCollationName = defGetQualifiedName(defel);
1470 }
1471 else if (strcmp(defel->defname, "canonical") == 0)
1472 {
1473 if (rangeCanonicalName != NIL)
1474 errorConflictingDefElem(defel, pstate);
1475 rangeCanonicalName = defGetQualifiedName(defel);
1476 }
1477 else if (strcmp(defel->defname, "subtype_diff") == 0)
1478 {
1479 if (rangeSubtypeDiffName != NIL)
1480 errorConflictingDefElem(defel, pstate);
1481 rangeSubtypeDiffName = defGetQualifiedName(defel);
1482 }
1483 else if (strcmp(defel->defname, "multirange_type_name") == 0)
1484 {
1485 if (multirangeTypeName != NULL)
1486 errorConflictingDefElem(defel, pstate);
1487 /* we can look up the subtype name immediately */
1488 multirangeNamespace = QualifiedNameGetCreationNamespace(defGetQualifiedName(defel),
1489 &multirangeTypeName);
1490 }
1491 else
1492 ereport(ERROR,
1493 (errcode(ERRCODE_SYNTAX_ERROR),
1494 errmsg("type attribute \"%s\" not recognized",
1495 defel->defname)));
1496 }
1497
1498 /* Must have a subtype */
1499 if (!OidIsValid(rangeSubtype))
1500 ereport(ERROR,
1501 (errcode(ERRCODE_SYNTAX_ERROR),
1502 errmsg("type attribute \"subtype\" is required")));
1503 /* disallow ranges of pseudotypes */
1504 if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
1505 ereport(ERROR,
1506 (errcode(ERRCODE_DATATYPE_MISMATCH),
1507 errmsg("range subtype cannot be %s",
1508 format_type_be(rangeSubtype))));
1509
1510 /* Identify subopclass */
1511 rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1512
1513 /* Identify collation to use, if any */
1514 if (type_is_collatable(rangeSubtype))
1515 {
1516 if (rangeCollationName != NIL)
1517 rangeCollation = get_collation_oid(rangeCollationName, false);
1518 else
1519 rangeCollation = get_typcollation(rangeSubtype);
1520 }
1521 else
1522 {
1523 if (rangeCollationName != NIL)
1524 ereport(ERROR,
1525 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1526 errmsg("range collation specified but subtype does not support collation")));
1527 rangeCollation = InvalidOid;
1528 }
1529
1530 /* Identify support functions, if provided */
1531 if (rangeCanonicalName != NIL)
1532 {
1533 if (!OidIsValid(typoid))
1534 ereport(ERROR,
1535 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1536 errmsg("cannot specify a canonical function without a pre-created shell type"),
1537 errhint("Create the type as a shell type, then create its canonicalization function, then do a full CREATE TYPE.")));
1538 rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1539 typoid);
1540 }
1541 else
1542 rangeCanonical = InvalidOid;
1543
1544 if (rangeSubtypeDiffName != NIL)
1545 rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1546 rangeSubtype);
1547 else
1548 rangeSubtypeDiff = InvalidOid;
1549
1550 get_typlenbyvalalign(rangeSubtype,
1551 &subtyplen, &subtypbyval, &subtypalign);
1552
1553 /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for ranges */
1554 alignment = (subtypalign == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
1555
1556 /* Allocate OID for array type, its multirange, and its multirange array */
1557 rangeArrayOid = AssignTypeArrayOid();
1558 multirangeOid = AssignTypeMultirangeOid();
1559 multirangeArrayOid = AssignTypeMultirangeArrayOid();
1560
1561 /* Create the pg_type entry */
1562 address =
1563 TypeCreate(InvalidOid, /* no predetermined type OID */
1564 typeName, /* type name */
1565 typeNamespace, /* namespace */
1566 InvalidOid, /* relation oid (n/a here) */
1567 0, /* relation kind (ditto) */
1568 GetUserId(), /* owner's ID */
1569 -1, /* internal size (always varlena) */
1570 TYPTYPE_RANGE, /* type-type (range type) */
1571 TYPCATEGORY_RANGE, /* type-category (range type) */
1572 false, /* range types are never preferred */
1573 DEFAULT_TYPDELIM, /* array element delimiter */
1574 F_RANGE_IN, /* input procedure */
1575 F_RANGE_OUT, /* output procedure */
1576 F_RANGE_RECV, /* receive procedure */
1577 F_RANGE_SEND, /* send procedure */
1578 InvalidOid, /* typmodin procedure - none */
1579 InvalidOid, /* typmodout procedure - none */
1580 F_RANGE_TYPANALYZE, /* analyze procedure */
1581 InvalidOid, /* subscript procedure - none */
1582 InvalidOid, /* element type ID - none */
1583 false, /* this is not an array type */
1584 rangeArrayOid, /* array type we are about to create */
1585 InvalidOid, /* base type ID (only for domains) */
1586 NULL, /* never a default type value */
1587 NULL, /* no binary form available either */
1588 false, /* never passed by value */
1589 alignment, /* alignment */
1590 TYPSTORAGE_EXTENDED, /* TOAST strategy (always extended) */
1591 -1, /* typMod (Domains only) */
1592 0, /* Array dimensions of typbasetype */
1593 false, /* Type NOT NULL */
1594 InvalidOid); /* type's collation (ranges never have one) */
1595 Assert(typoid == InvalidOid || typoid == address.objectId);
1596 typoid = address.objectId;
1597
1598 /* Create the multirange that goes with it */
1599 if (multirangeTypeName)
1600 {
1601 Oid old_typoid;
1602
1603 /*
1604 * Look to see if multirange type already exists.
1605 */
1606 old_typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
1607 CStringGetDatum(multirangeTypeName),
1608 ObjectIdGetDatum(multirangeNamespace));
1609
1610 /*
1611 * If it's not a shell, see if it's an autogenerated array type, and
1612 * if so rename it out of the way.
1613 */
1614 if (OidIsValid(old_typoid) && get_typisdefined(old_typoid))
1615 {
1616 if (!moveArrayTypeName(old_typoid, multirangeTypeName, multirangeNamespace))
1617 ereport(ERROR,
1619 errmsg("type \"%s\" already exists", multirangeTypeName)));
1620 }
1621 }
1622 else
1623 {
1624 /* Generate multirange name automatically */
1625 multirangeNamespace = typeNamespace;
1626 multirangeTypeName = makeMultirangeTypeName(typeName, multirangeNamespace);
1627 }
1628
1629 mltrngaddress =
1630 TypeCreate(multirangeOid, /* force assignment of this type OID */
1631 multirangeTypeName, /* type name */
1632 multirangeNamespace, /* namespace */
1633 InvalidOid, /* relation oid (n/a here) */
1634 0, /* relation kind (ditto) */
1635 GetUserId(), /* owner's ID */
1636 -1, /* internal size (always varlena) */
1637 TYPTYPE_MULTIRANGE, /* type-type (multirange type) */
1638 TYPCATEGORY_RANGE, /* type-category (range type) */
1639 false, /* multirange types are never preferred */
1640 DEFAULT_TYPDELIM, /* array element delimiter */
1641 F_MULTIRANGE_IN, /* input procedure */
1642 F_MULTIRANGE_OUT, /* output procedure */
1643 F_MULTIRANGE_RECV, /* receive procedure */
1644 F_MULTIRANGE_SEND, /* send procedure */
1645 InvalidOid, /* typmodin procedure - none */
1646 InvalidOid, /* typmodout procedure - none */
1647 F_MULTIRANGE_TYPANALYZE, /* analyze procedure */
1648 InvalidOid, /* subscript procedure - none */
1649 InvalidOid, /* element type ID - none */
1650 false, /* this is not an array type */
1651 multirangeArrayOid, /* array type we are about to create */
1652 InvalidOid, /* base type ID (only for domains) */
1653 NULL, /* never a default type value */
1654 NULL, /* no binary form available either */
1655 false, /* never passed by value */
1656 alignment, /* alignment */
1657 'x', /* TOAST strategy (always extended) */
1658 -1, /* typMod (Domains only) */
1659 0, /* Array dimensions of typbasetype */
1660 false, /* Type NOT NULL */
1661 InvalidOid); /* type's collation (ranges never have one) */
1662 Assert(multirangeOid == mltrngaddress.objectId);
1663
1664 /* Create the entry in pg_range */
1665 RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1666 rangeCanonical, rangeSubtypeDiff, multirangeOid);
1667
1668 /*
1669 * Create the array type that goes with it.
1670 */
1671 rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1672
1673 TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1674 rangeArrayName, /* type name */
1675 typeNamespace, /* namespace */
1676 InvalidOid, /* relation oid (n/a here) */
1677 0, /* relation kind (ditto) */
1678 GetUserId(), /* owner's ID */
1679 -1, /* internal size (always varlena) */
1680 TYPTYPE_BASE, /* type-type (base type) */
1681 TYPCATEGORY_ARRAY, /* type-category (array) */
1682 false, /* array types are never preferred */
1683 DEFAULT_TYPDELIM, /* array element delimiter */
1684 F_ARRAY_IN, /* input procedure */
1685 F_ARRAY_OUT, /* output procedure */
1686 F_ARRAY_RECV, /* receive procedure */
1687 F_ARRAY_SEND, /* send procedure */
1688 InvalidOid, /* typmodin procedure - none */
1689 InvalidOid, /* typmodout procedure - none */
1690 F_ARRAY_TYPANALYZE, /* analyze procedure */
1691 F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1692 typoid, /* element type ID */
1693 true, /* yes this is an array type */
1694 InvalidOid, /* no further array type */
1695 InvalidOid, /* base type ID */
1696 NULL, /* never a default type value */
1697 NULL, /* binary default isn't sent either */
1698 false, /* never passed by value */
1699 alignment, /* alignment - same as range's */
1700 TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
1701 -1, /* typMod (Domains only) */
1702 0, /* Array dimensions of typbasetype */
1703 false, /* Type NOT NULL */
1704 InvalidOid); /* typcollation */
1705
1706 pfree(rangeArrayName);
1707
1708 /* Create the multirange's array type */
1709
1710 multirangeArrayName = makeArrayTypeName(multirangeTypeName, typeNamespace);
1711
1712 TypeCreate(multirangeArrayOid, /* force assignment of this type OID */
1713 multirangeArrayName, /* type name */
1714 multirangeNamespace, /* namespace */
1715 InvalidOid, /* relation oid (n/a here) */
1716 0, /* relation kind (ditto) */
1717 GetUserId(), /* owner's ID */
1718 -1, /* internal size (always varlena) */
1719 TYPTYPE_BASE, /* type-type (base type) */
1720 TYPCATEGORY_ARRAY, /* type-category (array) */
1721 false, /* array types are never preferred */
1722 DEFAULT_TYPDELIM, /* array element delimiter */
1723 F_ARRAY_IN, /* input procedure */
1724 F_ARRAY_OUT, /* output procedure */
1725 F_ARRAY_RECV, /* receive procedure */
1726 F_ARRAY_SEND, /* send procedure */
1727 InvalidOid, /* typmodin procedure - none */
1728 InvalidOid, /* typmodout procedure - none */
1729 F_ARRAY_TYPANALYZE, /* analyze procedure */
1730 F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1731 multirangeOid, /* element type ID */
1732 true, /* yes this is an array type */
1733 InvalidOid, /* no further array type */
1734 InvalidOid, /* base type ID */
1735 NULL, /* never a default type value */
1736 NULL, /* binary default isn't sent either */
1737 false, /* never passed by value */
1738 alignment, /* alignment - same as range's */
1739 'x', /* ARRAY is always toastable */
1740 -1, /* typMod (Domains only) */
1741 0, /* Array dimensions of typbasetype */
1742 false, /* Type NOT NULL */
1743 InvalidOid); /* typcollation */
1744
1745 /* Ensure these new types are visible to ProcedureCreate */
1747
1748 /* And create the constructor functions for this range type */
1749 makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1750 makeMultirangeConstructors(multirangeTypeName, typeNamespace,
1751 multirangeOid, typoid, rangeArrayOid,
1752 &castFuncOid);
1753
1754 /* Create cast from the range type to its multirange type */
1755 CastCreate(typoid, multirangeOid, castFuncOid, InvalidOid, InvalidOid,
1756 COERCION_CODE_EXPLICIT, COERCION_METHOD_FUNCTION,
1758
1759 pfree(multirangeArrayName);
1760
1761 return address;
1762}
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:228
Oid regproc
Definition: c.h:657
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:271
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:371
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:2340
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2438
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:3223
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:3248
ObjectAddress CastCreate(Oid sourcetypeid, Oid targettypeid, Oid funcid, Oid incastid, Oid outcastid, char castcontext, char castmethod, DependencyType behavior)
Definition: pg_cast.c:49
void RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, Oid rangeSubOpclass, RegProcedure rangeCanonical, RegProcedure rangeSubDiff, Oid multirangeTypeOid)
Definition: pg_range.c:36
char * makeMultirangeTypeName(const char *rangeTypeName, Oid typeNamespace)
Definition: pg_type.c:948
Oid AssignTypeMultirangeOid(void)
Definition: typecmds.c:2484
static Oid findRangeSubOpclass(List *opcname, Oid subtype)
Definition: typecmds.c:2323
static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype)
Definition: typecmds.c:2403
static void makeMultirangeConstructors(const char *name, Oid namespace, Oid multirangeOid, Oid rangeOid, Oid rangeArrayOid, Oid *castFuncOid)
Definition: typecmds.c:1849
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2362
static void makeRangeConstructors(const char *name, Oid namespace, Oid rangeOid, Oid subtype)
Definition: typecmds.c:1774
Oid AssignTypeMultirangeArrayOid(void)
Definition: typecmds.c:2517

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, Assert(), AssignTypeArrayOid(), AssignTypeMultirangeArrayOid(), AssignTypeMultirangeOid(), CastCreate(), CommandCounterIncrement(), CStringGetDatum(), DEFAULT_TYPDELIM, defGetQualifiedName(), defGetTypeName(), DefElem::defname, DEPENDENCY_INTERNAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg(), ERROR, errorConflictingDefElem(), findRangeCanonicalFunction(), findRangeSubOpclass(), findRangeSubtypeDiffFunction(), format_type_be(), get_collation_oid(), get_namespace_name(), get_typcollation(), get_typisdefined(), get_typlenbyvalalign(), get_typtype(), GetSysCacheOid2, GetUserId(), InvalidOid, lfirst, makeArrayTypeName(), makeMultirangeConstructors(), makeMultirangeTypeName(), makeRangeConstructors(), moveArrayTypeName(), NIL, object_aclcheck(), OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, pfree(), PG_USED_FOR_ASSERTS_ONLY, QualifiedNameGetCreationNamespace(), RangeCreate(), stmt, type_is_collatable(), TypeCreate(), and typenameTypeId().

Referenced by ProcessUtilitySlow().

◆ DefineType()

ObjectAddress DefineType ( ParseState pstate,
List names,
List parameters 
)

Definition at line 152 of file typecmds.c.

153{
154 char *typeName;
155 Oid typeNamespace;
156 int16 internalLength = -1; /* default: variable-length */
157 List *inputName = NIL;
158 List *outputName = NIL;
159 List *receiveName = NIL;
160 List *sendName = NIL;
161 List *typmodinName = NIL;
162 List *typmodoutName = NIL;
163 List *analyzeName = NIL;
164 List *subscriptName = NIL;
165 char category = TYPCATEGORY_USER;
166 bool preferred = false;
167 char delimiter = DEFAULT_TYPDELIM;
168 Oid elemType = InvalidOid;
169 char *defaultValue = NULL;
170 bool byValue = false;
171 char alignment = TYPALIGN_INT; /* default alignment */
172 char storage = TYPSTORAGE_PLAIN; /* default TOAST storage method */
173 Oid collation = InvalidOid;
174 DefElem *likeTypeEl = NULL;
175 DefElem *internalLengthEl = NULL;
176 DefElem *inputNameEl = NULL;
177 DefElem *outputNameEl = NULL;
178 DefElem *receiveNameEl = NULL;
179 DefElem *sendNameEl = NULL;
180 DefElem *typmodinNameEl = NULL;
181 DefElem *typmodoutNameEl = NULL;
182 DefElem *analyzeNameEl = NULL;
183 DefElem *subscriptNameEl = NULL;
184 DefElem *categoryEl = NULL;
185 DefElem *preferredEl = NULL;
186 DefElem *delimiterEl = NULL;
187 DefElem *elemTypeEl = NULL;
188 DefElem *defaultValueEl = NULL;
189 DefElem *byValueEl = NULL;
190 DefElem *alignmentEl = NULL;
191 DefElem *storageEl = NULL;
192 DefElem *collatableEl = NULL;
193 Oid inputOid;
194 Oid outputOid;
195 Oid receiveOid = InvalidOid;
196 Oid sendOid = InvalidOid;
197 Oid typmodinOid = InvalidOid;
198 Oid typmodoutOid = InvalidOid;
199 Oid analyzeOid = InvalidOid;
200 Oid subscriptOid = InvalidOid;
201 char *array_type;
202 Oid array_oid;
203 Oid typoid;
204 ListCell *pl;
205 ObjectAddress address;
206
207 /*
208 * As of Postgres 8.4, we require superuser privilege to create a base
209 * type. This is simple paranoia: there are too many ways to mess up the
210 * system with an incorrect type definition (for instance, representation
211 * parameters that don't match what the C code expects). In practice it
212 * takes superuser privilege to create the I/O functions, and so the
213 * former requirement that you own the I/O functions pretty much forced
214 * superuserness anyway. We're just making doubly sure here.
215 *
216 * XXX re-enable NOT_USED code sections below if you remove this test.
217 */
218 if (!superuser())
220 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
221 errmsg("must be superuser to create a base type")));
222
223 /* Convert list of names to a name and namespace */
224 typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
225
226#ifdef NOT_USED
227 /* XXX this is unnecessary given the superuser check above */
228 /* Check we have creation rights in target namespace */
229 aclresult = object_aclcheck(NamespaceRelationId, typeNamespace, GetUserId(), ACL_CREATE);
230 if (aclresult != ACLCHECK_OK)
231 aclcheck_error(aclresult, OBJECT_SCHEMA,
232 get_namespace_name(typeNamespace));
233#endif
234
235 /*
236 * Look to see if type already exists.
237 */
238 typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
239 CStringGetDatum(typeName),
240 ObjectIdGetDatum(typeNamespace));
241
242 /*
243 * If it's not a shell, see if it's an autogenerated array type, and if so
244 * rename it out of the way.
245 */
246 if (OidIsValid(typoid) && get_typisdefined(typoid))
247 {
248 if (moveArrayTypeName(typoid, typeName, typeNamespace))
249 typoid = InvalidOid;
250 else
253 errmsg("type \"%s\" already exists", typeName)));
254 }
255
256 /*
257 * If this command is a parameterless CREATE TYPE, then we're just here to
258 * make a shell type, so do that (or fail if there already is a shell).
259 */
260 if (parameters == NIL)
261 {
262 if (OidIsValid(typoid))
265 errmsg("type \"%s\" already exists", typeName)));
266
267 address = TypeShellMake(typeName, typeNamespace, GetUserId());
268 return address;
269 }
270
271 /*
272 * Otherwise, we must already have a shell type, since there is no other
273 * way that the I/O functions could have been created.
274 */
275 if (!OidIsValid(typoid))
278 errmsg("type \"%s\" does not exist", typeName),
279 errhint("Create the type as a shell type, then create its I/O functions, then do a full CREATE TYPE.")));
280
281 /* Extract the parameters from the parameter list */
282 foreach(pl, parameters)
283 {
284 DefElem *defel = (DefElem *) lfirst(pl);
285 DefElem **defelp;
286
287 if (strcmp(defel->defname, "like") == 0)
288 defelp = &likeTypeEl;
289 else if (strcmp(defel->defname, "internallength") == 0)
290 defelp = &internalLengthEl;
291 else if (strcmp(defel->defname, "input") == 0)
292 defelp = &inputNameEl;
293 else if (strcmp(defel->defname, "output") == 0)
294 defelp = &outputNameEl;
295 else if (strcmp(defel->defname, "receive") == 0)
296 defelp = &receiveNameEl;
297 else if (strcmp(defel->defname, "send") == 0)
298 defelp = &sendNameEl;
299 else if (strcmp(defel->defname, "typmod_in") == 0)
300 defelp = &typmodinNameEl;
301 else if (strcmp(defel->defname, "typmod_out") == 0)
302 defelp = &typmodoutNameEl;
303 else if (strcmp(defel->defname, "analyze") == 0 ||
304 strcmp(defel->defname, "analyse") == 0)
305 defelp = &analyzeNameEl;
306 else if (strcmp(defel->defname, "subscript") == 0)
307 defelp = &subscriptNameEl;
308 else if (strcmp(defel->defname, "category") == 0)
309 defelp = &categoryEl;
310 else if (strcmp(defel->defname, "preferred") == 0)
311 defelp = &preferredEl;
312 else if (strcmp(defel->defname, "delimiter") == 0)
313 defelp = &delimiterEl;
314 else if (strcmp(defel->defname, "element") == 0)
315 defelp = &elemTypeEl;
316 else if (strcmp(defel->defname, "default") == 0)
317 defelp = &defaultValueEl;
318 else if (strcmp(defel->defname, "passedbyvalue") == 0)
319 defelp = &byValueEl;
320 else if (strcmp(defel->defname, "alignment") == 0)
321 defelp = &alignmentEl;
322 else if (strcmp(defel->defname, "storage") == 0)
323 defelp = &storageEl;
324 else if (strcmp(defel->defname, "collatable") == 0)
325 defelp = &collatableEl;
326 else
327 {
328 /* WARNING, not ERROR, for historical backwards-compatibility */
330 (errcode(ERRCODE_SYNTAX_ERROR),
331 errmsg("type attribute \"%s\" not recognized",
332 defel->defname),
333 parser_errposition(pstate, defel->location)));
334 continue;
335 }
336 if (*defelp != NULL)
337 errorConflictingDefElem(defel, pstate);
338 *defelp = defel;
339 }
340
341 /*
342 * Now interpret the options; we do this separately so that LIKE can be
343 * overridden by other options regardless of the ordering in the parameter
344 * list.
345 */
346 if (likeTypeEl)
347 {
348 Type likeType;
349 Form_pg_type likeForm;
350
351 likeType = typenameType(pstate, defGetTypeName(likeTypeEl), NULL);
352 likeForm = (Form_pg_type) GETSTRUCT(likeType);
353 internalLength = likeForm->typlen;
354 byValue = likeForm->typbyval;
355 alignment = likeForm->typalign;
356 storage = likeForm->typstorage;
357 ReleaseSysCache(likeType);
358 }
359 if (internalLengthEl)
360 internalLength = defGetTypeLength(internalLengthEl);
361 if (inputNameEl)
362 inputName = defGetQualifiedName(inputNameEl);
363 if (outputNameEl)
364 outputName = defGetQualifiedName(outputNameEl);
365 if (receiveNameEl)
366 receiveName = defGetQualifiedName(receiveNameEl);
367 if (sendNameEl)
368 sendName = defGetQualifiedName(sendNameEl);
369 if (typmodinNameEl)
370 typmodinName = defGetQualifiedName(typmodinNameEl);
371 if (typmodoutNameEl)
372 typmodoutName = defGetQualifiedName(typmodoutNameEl);
373 if (analyzeNameEl)
374 analyzeName = defGetQualifiedName(analyzeNameEl);
375 if (subscriptNameEl)
376 subscriptName = defGetQualifiedName(subscriptNameEl);
377 if (categoryEl)
378 {
379 char *p = defGetString(categoryEl);
380
381 category = p[0];
382 /* restrict to non-control ASCII */
383 if (category < 32 || category > 126)
385 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
386 errmsg("invalid type category \"%s\": must be simple ASCII",
387 p)));
388 }
389 if (preferredEl)
390 preferred = defGetBoolean(preferredEl);
391 if (delimiterEl)
392 {
393 char *p = defGetString(delimiterEl);
394
395 delimiter = p[0];
396 /* XXX shouldn't we restrict the delimiter? */
397 }
398 if (elemTypeEl)
399 {
400 elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
401 /* disallow arrays of pseudotypes */
402 if (get_typtype(elemType) == TYPTYPE_PSEUDO)
404 (errcode(ERRCODE_DATATYPE_MISMATCH),
405 errmsg("array element type cannot be %s",
406 format_type_be(elemType))));
407 }
408 if (defaultValueEl)
409 defaultValue = defGetString(defaultValueEl);
410 if (byValueEl)
411 byValue = defGetBoolean(byValueEl);
412 if (alignmentEl)
413 {
414 char *a = defGetString(alignmentEl);
415
416 /*
417 * Note: if argument was an unquoted identifier, parser will have
418 * applied translations to it, so be prepared to recognize translated
419 * type names as well as the nominal form.
420 */
421 if (pg_strcasecmp(a, "double") == 0 ||
422 pg_strcasecmp(a, "float8") == 0 ||
423 pg_strcasecmp(a, "pg_catalog.float8") == 0)
424 alignment = TYPALIGN_DOUBLE;
425 else if (pg_strcasecmp(a, "int4") == 0 ||
426 pg_strcasecmp(a, "pg_catalog.int4") == 0)
427 alignment = TYPALIGN_INT;
428 else if (pg_strcasecmp(a, "int2") == 0 ||
429 pg_strcasecmp(a, "pg_catalog.int2") == 0)
430 alignment = TYPALIGN_SHORT;
431 else if (pg_strcasecmp(a, "char") == 0 ||
432 pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
433 alignment = TYPALIGN_CHAR;
434 else
436 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
437 errmsg("alignment \"%s\" not recognized", a)));
438 }
439 if (storageEl)
440 {
441 char *a = defGetString(storageEl);
442
443 if (pg_strcasecmp(a, "plain") == 0)
444 storage = TYPSTORAGE_PLAIN;
445 else if (pg_strcasecmp(a, "external") == 0)
446 storage = TYPSTORAGE_EXTERNAL;
447 else if (pg_strcasecmp(a, "extended") == 0)
448 storage = TYPSTORAGE_EXTENDED;
449 else if (pg_strcasecmp(a, "main") == 0)
450 storage = TYPSTORAGE_MAIN;
451 else
453 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
454 errmsg("storage \"%s\" not recognized", a)));
455 }
456 if (collatableEl)
457 collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
458
459 /*
460 * make sure we have our required definitions
461 */
462 if (inputName == NIL)
464 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
465 errmsg("type input function must be specified")));
466 if (outputName == NIL)
468 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
469 errmsg("type output function must be specified")));
470
471 if (typmodinName == NIL && typmodoutName != NIL)
473 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
474 errmsg("type modifier output function is useless without a type modifier input function")));
475
476 /*
477 * Convert I/O proc names to OIDs
478 */
479 inputOid = findTypeInputFunction(inputName, typoid);
480 outputOid = findTypeOutputFunction(outputName, typoid);
481 if (receiveName)
482 receiveOid = findTypeReceiveFunction(receiveName, typoid);
483 if (sendName)
484 sendOid = findTypeSendFunction(sendName, typoid);
485
486 /*
487 * Convert typmodin/out function proc names to OIDs.
488 */
489 if (typmodinName)
490 typmodinOid = findTypeTypmodinFunction(typmodinName);
491 if (typmodoutName)
492 typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
493
494 /*
495 * Convert analysis function proc name to an OID. If no analysis function
496 * is specified, we'll use zero to select the built-in default algorithm.
497 */
498 if (analyzeName)
499 analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
500
501 /*
502 * Likewise look up the subscripting function if any. If it is not
503 * specified, but a typelem is specified, allow that if
504 * raw_array_subscript_handler can be used. (This is for backwards
505 * compatibility; maybe someday we should throw an error instead.)
506 */
507 if (subscriptName)
508 subscriptOid = findTypeSubscriptingFunction(subscriptName, typoid);
509 else if (OidIsValid(elemType))
510 {
511 if (internalLength > 0 && !byValue && get_typlen(elemType) > 0)
512 subscriptOid = F_RAW_ARRAY_SUBSCRIPT_HANDLER;
513 else
515 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
516 errmsg("element type cannot be specified without a subscripting function")));
517 }
518
519 /*
520 * Check permissions on functions. We choose to require the creator/owner
521 * of a type to also own the underlying functions. Since creating a type
522 * is tantamount to granting public execute access on the functions, the
523 * minimum sane check would be for execute-with-grant-option. But we
524 * don't have a way to make the type go away if the grant option is
525 * revoked, so ownership seems better.
526 *
527 * XXX For now, this is all unnecessary given the superuser check above.
528 * If we ever relax that, these calls likely should be moved into
529 * findTypeInputFunction et al, where they could be shared by AlterType.
530 */
531#ifdef NOT_USED
532 if (inputOid && !object_ownercheck(ProcedureRelationId, inputOid, GetUserId()))
534 NameListToString(inputName));
535 if (outputOid && !object_ownercheck(ProcedureRelationId, outputOid, GetUserId()))
537 NameListToString(outputName));
538 if (receiveOid && !object_ownercheck(ProcedureRelationId, receiveOid, GetUserId()))
540 NameListToString(receiveName));
541 if (sendOid && !object_ownercheck(ProcedureRelationId, sendOid, GetUserId()))
543 NameListToString(sendName));
544 if (typmodinOid && !object_ownercheck(ProcedureRelationId, typmodinOid, GetUserId()))
546 NameListToString(typmodinName));
547 if (typmodoutOid && !object_ownercheck(ProcedureRelationId, typmodoutOid, GetUserId()))
549 NameListToString(typmodoutName));
550 if (analyzeOid && !object_ownercheck(ProcedureRelationId, analyzeOid, GetUserId()))
552 NameListToString(analyzeName));
553 if (subscriptOid && !object_ownercheck(ProcedureRelationId, subscriptOid, GetUserId()))
555 NameListToString(subscriptName));
556#endif
557
558 /*
559 * OK, we're done checking, time to make the type. We must assign the
560 * array type OID ahead of calling TypeCreate, since the base type and
561 * array type each refer to the other.
562 */
563 array_oid = AssignTypeArrayOid();
564
565 /*
566 * now have TypeCreate do all the real work.
567 *
568 * Note: the pg_type.oid is stored in user tables as array elements (base
569 * types) in ArrayType and in composite types in DatumTupleFields. This
570 * oid must be preserved by binary upgrades.
571 */
572 address =
573 TypeCreate(InvalidOid, /* no predetermined type OID */
574 typeName, /* type name */
575 typeNamespace, /* namespace */
576 InvalidOid, /* relation oid (n/a here) */
577 0, /* relation kind (ditto) */
578 GetUserId(), /* owner's ID */
579 internalLength, /* internal size */
580 TYPTYPE_BASE, /* type-type (base type) */
581 category, /* type-category */
582 preferred, /* is it a preferred type? */
583 delimiter, /* array element delimiter */
584 inputOid, /* input procedure */
585 outputOid, /* output procedure */
586 receiveOid, /* receive procedure */
587 sendOid, /* send procedure */
588 typmodinOid, /* typmodin procedure */
589 typmodoutOid, /* typmodout procedure */
590 analyzeOid, /* analyze procedure */
591 subscriptOid, /* subscript procedure */
592 elemType, /* element type ID */
593 false, /* this is not an implicit array type */
594 array_oid, /* array type we are about to create */
595 InvalidOid, /* base type ID (only for domains) */
596 defaultValue, /* default type value */
597 NULL, /* no binary form available */
598 byValue, /* passed by value */
599 alignment, /* required alignment */
600 storage, /* TOAST strategy */
601 -1, /* typMod (Domains only) */
602 0, /* Array Dimensions of typbasetype */
603 false, /* Type NOT NULL */
604 collation); /* type's collation */
605 Assert(typoid == address.objectId);
606
607 /*
608 * Create the array type that goes with it.
609 */
610 array_type = makeArrayTypeName(typeName, typeNamespace);
611
612 /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for arrays */
613 alignment = (alignment == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
614
615 TypeCreate(array_oid, /* force assignment of this type OID */
616 array_type, /* type name */
617 typeNamespace, /* namespace */
618 InvalidOid, /* relation oid (n/a here) */
619 0, /* relation kind (ditto) */
620 GetUserId(), /* owner's ID */
621 -1, /* internal size (always varlena) */
622 TYPTYPE_BASE, /* type-type (base type) */
623 TYPCATEGORY_ARRAY, /* type-category (array) */
624 false, /* array types are never preferred */
625 delimiter, /* array element delimiter */
626 F_ARRAY_IN, /* input procedure */
627 F_ARRAY_OUT, /* output procedure */
628 F_ARRAY_RECV, /* receive procedure */
629 F_ARRAY_SEND, /* send procedure */
630 typmodinOid, /* typmodin procedure */
631 typmodoutOid, /* typmodout procedure */
632 F_ARRAY_TYPANALYZE, /* analyze procedure */
633 F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
634 typoid, /* element type ID */
635 true, /* yes this is an array type */
636 InvalidOid, /* no further array type */
637 InvalidOid, /* base type ID */
638 NULL, /* never a default type value */
639 NULL, /* binary default isn't sent either */
640 false, /* never passed by value */
641 alignment, /* see above */
642 TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
643 -1, /* typMod (Domains only) */
644 0, /* Array dimensions of typbasetype */
645 false, /* Type NOT NULL */
646 collation); /* type's collation */
647
648 pfree(array_type);
649
650 return address;
651}
int defGetTypeLength(DefElem *def)
Definition: define.c:299
bool defGetBoolean(DefElem *def)
Definition: define.c:94
#define WARNING
Definition: elog.h:36
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2364
char * NameListToString(const List *names)
Definition: namespace.c:3664
@ OBJECT_FUNCTION
Definition: parsenodes.h:2344
ObjectAddress TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
Definition: pg_type.c:57
ParseLoc location
Definition: parsenodes.h:847
static Oid findTypeOutputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2057
static Oid findTypeInputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1994

References a, ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, Assert(), AssignTypeArrayOid(), CStringGetDatum(), DEFAULT_TYPDELIM, defGetBoolean(), defGetQualifiedName(), defGetString(), defGetTypeLength(), defGetTypeName(), DefElem::defname, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg(), ERROR, errorConflictingDefElem(), findTypeAnalyzeFunction(), findTypeInputFunction(), findTypeOutputFunction(), findTypeReceiveFunction(), findTypeSendFunction(), findTypeSubscriptingFunction(), findTypeTypmodinFunction(), findTypeTypmodoutFunction(), format_type_be(), get_namespace_name(), get_typisdefined(), get_typlen(), get_typtype(), GETSTRUCT(), GetSysCacheOid2, GetUserId(), InvalidOid, lfirst, DefElem::location, makeArrayTypeName(), moveArrayTypeName(), NameListToString(), NIL, object_aclcheck(), OBJECT_FUNCTION, object_ownercheck(), OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, parser_errposition(), pfree(), pg_strcasecmp(), QualifiedNameGetCreationNamespace(), ReleaseSysCache(), storage, superuser(), TypeCreate(), typenameType(), typenameTypeId(), TypeShellMake(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ RemoveTypeById()

void RemoveTypeById ( Oid  typeOid)

Definition at line 657 of file typecmds.c.

658{
659 Relation relation;
660 HeapTuple tup;
661
662 relation = table_open(TypeRelationId, RowExclusiveLock);
663
664 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
665 if (!HeapTupleIsValid(tup))
666 elog(ERROR, "cache lookup failed for type %u", typeOid);
667
668 CatalogTupleDelete(relation, &tup->t_self);
669
670 /*
671 * If it is an enum, delete the pg_enum entries too; we don't bother with
672 * making dependency entries for those, so it has to be done "by hand"
673 * here.
674 */
675 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
676 EnumValuesDelete(typeOid);
677
678 /*
679 * If it is a range type, delete the pg_range entry too; we don't bother
680 * with making a dependency entry for that, so it has to be done "by hand"
681 * here.
682 */
683 if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
684 RangeDelete(typeOid);
685
686 ReleaseSysCache(tup);
687
688 table_close(relation, RowExclusiveLock);
689}
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition: indexing.c:365
void EnumValuesDelete(Oid enumTypeOid)
Definition: pg_enum.c:237
void RangeDelete(Oid rangeTypeOid)
Definition: pg_range.c:113

References CatalogTupleDelete(), elog, EnumValuesDelete(), ERROR, GETSTRUCT(), HeapTupleIsValid, ObjectIdGetDatum(), RangeDelete(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

◆ RenameType()

ObjectAddress RenameType ( RenameStmt stmt)

Definition at line 3754 of file typecmds.c.

3755{
3756 List *names = castNode(List, stmt->object);
3757 const char *newTypeName = stmt->newname;
3758 TypeName *typename;
3759 Oid typeOid;
3760 Relation rel;
3761 HeapTuple tup;
3762 Form_pg_type typTup;
3763 ObjectAddress address;
3764
3765 /* Make a TypeName so we can use standard type lookup machinery */
3766 typename = makeTypeNameFromNameList(names);
3767 typeOid = typenameTypeId(NULL, typename);
3768
3769 /* Look up the type in the type table */
3770 rel = table_open(TypeRelationId, RowExclusiveLock);
3771
3772 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3773 if (!HeapTupleIsValid(tup))
3774 elog(ERROR, "cache lookup failed for type %u", typeOid);
3775 typTup = (Form_pg_type) GETSTRUCT(tup);
3776
3777 /* check permissions on type */
3778 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
3780
3781 /* ALTER DOMAIN used on a non-domain? */
3782 if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3783 ereport(ERROR,
3784 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3785 errmsg("%s is not a domain",
3786 format_type_be(typeOid))));
3787
3788 /*
3789 * If it's a composite type, we need to check that it really is a
3790 * free-standing composite type, and not a table's rowtype. We want people
3791 * to use ALTER TABLE not ALTER TYPE for that case.
3792 */
3793 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3794 get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3795 ereport(ERROR,
3796 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3797 errmsg("%s is a table's row type",
3798 format_type_be(typeOid)),
3799 /* translator: %s is an SQL ALTER command */
3800 errhint("Use %s instead.",
3801 "ALTER TABLE")));
3802
3803 /* don't allow direct alteration of array types, either */
3804 if (IsTrueArrayType(typTup))
3805 ereport(ERROR,
3806 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3807 errmsg("cannot alter array type %s",
3808 format_type_be(typeOid)),
3809 errhint("You can alter type %s, which will alter the array type as well.",
3810 format_type_be(typTup->typelem))));
3811
3812 /* we do allow separate renaming of multirange types, though */
3813
3814 /*
3815 * If type is composite we need to rename associated pg_class entry too.
3816 * RenameRelationInternal will call RenameTypeInternal automatically.
3817 */
3818 if (typTup->typtype == TYPTYPE_COMPOSITE)
3819 RenameRelationInternal(typTup->typrelid, newTypeName, false, false);
3820 else
3821 RenameTypeInternal(typeOid, newTypeName,
3822 typTup->typnamespace);
3823
3824 ObjectAddressSet(address, TypeRelationId, typeOid);
3825 /* Clean up */
3827
3828 return address;
3829}
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:763
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:4262

References aclcheck_error_type(), ACLCHECK_NOT_OWNER, castNode, elog, ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), get_rel_relkind(), GETSTRUCT(), GetUserId(), HeapTupleIsValid, makeTypeNameFromNameList(), OBJECT_DOMAIN, object_ownercheck(), ObjectAddressSet, ObjectIdGetDatum(), RenameRelationInternal(), RenameTypeInternal(), RowExclusiveLock, SearchSysCacheCopy1, stmt, table_close(), table_open(), and typenameTypeId().

Referenced by ExecRenameStmt().