Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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 2935 of file typecmds.c.

2937{
2938 TypeName *typename;
2939 Oid domainoid;
2940 Relation typrel;
2941 HeapTuple tup;
2942 Form_pg_type typTup;
2943 Constraint *constr;
2944 char *ccbin;
2946
2947 /* Make a TypeName so we can use standard type lookup machinery */
2948 typename = makeTypeNameFromNameList(names);
2949 domainoid = typenameTypeId(NULL, typename);
2950
2951 /* Look up the domain in the type table */
2952 typrel = table_open(TypeRelationId, RowExclusiveLock);
2953
2954 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2955 if (!HeapTupleIsValid(tup))
2956 elog(ERROR, "cache lookup failed for type %u", domainoid);
2957 typTup = (Form_pg_type) GETSTRUCT(tup);
2958
2959 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2960 checkDomainOwner(tup);
2961
2962 if (!IsA(newConstraint, Constraint))
2963 elog(ERROR, "unrecognized node type: %d",
2964 (int) nodeTag(newConstraint));
2965
2966 constr = (Constraint *) newConstraint;
2967
2968 /* enforced by parser */
2969 Assert(constr->contype == CONSTR_CHECK || constr->contype == CONSTR_NOTNULL);
2970
2971 if (constr->contype == CONSTR_CHECK)
2972 {
2973 /*
2974 * First, process the constraint expression and add an entry to
2975 * pg_constraint.
2976 */
2977
2978 ccbin = domainAddCheckConstraint(domainoid, typTup->typnamespace,
2979 typTup->typbasetype, typTup->typtypmod,
2980 constr, NameStr(typTup->typname), constrAddr);
2981
2982
2983 /*
2984 * If requested to validate the constraint, test all values stored in
2985 * the attributes based on the domain the constraint is being added
2986 * to.
2987 */
2988 if (!constr->skip_validation)
2989 validateDomainCheckConstraint(domainoid, ccbin, ShareLock);
2990
2991 /*
2992 * We must send out an sinval message for the domain, to ensure that
2993 * any dependent plans get rebuilt. Since this command doesn't change
2994 * the domain's pg_type row, that won't happen automatically; do it
2995 * manually.
2996 */
2997 CacheInvalidateHeapTuple(typrel, tup, NULL);
2998 }
2999 else if (constr->contype == CONSTR_NOTNULL)
3000 {
3001 /* Is the domain already set NOT NULL? */
3002 if (typTup->typnotnull)
3003 {
3005 return address;
3006 }
3007 domainAddNotNullConstraint(domainoid, typTup->typnamespace,
3008 typTup->typbasetype, typTup->typtypmod,
3009 constr, NameStr(typTup->typname), constrAddr);
3010
3011 if (!constr->skip_validation)
3013
3014 typTup->typnotnull = true;
3015 CatalogTupleUpdate(typrel, &tup->t_self, tup);
3016 }
3017
3018 ObjectAddressSet(address, TypeRelationId, domainoid);
3019
3020 /* Clean up */
3022
3023 return address;
3024}
#define NameStr(name)
Definition: c.h:752
#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, ItemPointer 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:2800
@ CONSTR_CHECK
Definition: parsenodes.h:2804
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:2832
bool skip_validation
Definition: parsenodes.h:2837
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:3515
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3495
static void domainAddNotNullConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:3675
static void validateDomainNotNullConstraint(Oid domainoid)
Definition: typecmds.c:3136
static void validateDomainCheckConstraint(Oid domainoid, const char *ccbin, LOCKMODE lockmode)
Definition: typecmds.c:3208

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 2614 of file typecmds.c.

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

2831{
2832 TypeName *typename;
2833 Oid domainoid;
2834 HeapTuple tup;
2835 Relation rel;
2836 Relation conrel;
2837 SysScanDesc conscan;
2838 ScanKeyData skey[3];
2839 HeapTuple contup;
2840 bool found = false;
2841 ObjectAddress address;
2842
2843 /* Make a TypeName so we can use standard type lookup machinery */
2844 typename = makeTypeNameFromNameList(names);
2845 domainoid = typenameTypeId(NULL, typename);
2846
2847 /* Look up the domain in the type table */
2848 rel = table_open(TypeRelationId, RowExclusiveLock);
2849
2850 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2851 if (!HeapTupleIsValid(tup))
2852 elog(ERROR, "cache lookup failed for type %u", domainoid);
2853
2854 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2855 checkDomainOwner(tup);
2856
2857 /* Grab an appropriate lock on the pg_constraint relation */
2858 conrel = table_open(ConstraintRelationId, RowExclusiveLock);
2859
2860 /* Find and remove the target constraint */
2861 ScanKeyInit(&skey[0],
2862 Anum_pg_constraint_conrelid,
2863 BTEqualStrategyNumber, F_OIDEQ,
2865 ScanKeyInit(&skey[1],
2866 Anum_pg_constraint_contypid,
2867 BTEqualStrategyNumber, F_OIDEQ,
2868 ObjectIdGetDatum(domainoid));
2869 ScanKeyInit(&skey[2],
2870 Anum_pg_constraint_conname,
2871 BTEqualStrategyNumber, F_NAMEEQ,
2872 CStringGetDatum(constrName));
2873
2874 conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
2875 NULL, 3, skey);
2876
2877 /* There can be at most one matching row */
2878 if ((contup = systable_getnext(conscan)) != NULL)
2879 {
2880 Form_pg_constraint construct = (Form_pg_constraint) GETSTRUCT(contup);
2881 ObjectAddress conobj;
2882
2883 if (construct->contype == CONSTRAINT_NOTNULL)
2884 {
2885 ((Form_pg_type) GETSTRUCT(tup))->typnotnull = false;
2886 CatalogTupleUpdate(rel, &tup->t_self, tup);
2887 }
2888
2889 conobj.classId = ConstraintRelationId;
2890 conobj.objectId = construct->oid;
2891 conobj.objectSubId = 0;
2892
2893 performDeletion(&conobj, behavior, 0);
2894 found = true;
2895 }
2896
2897 /* Clean up after the scan */
2898 systable_endscan(conscan);
2900
2901 if (!found)
2902 {
2903 if (!missing_ok)
2904 ereport(ERROR,
2905 (errcode(ERRCODE_UNDEFINED_OBJECT),
2906 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2907 constrName, TypeNameToString(typename))));
2908 else
2910 (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2911 constrName, TypeNameToString(typename))));
2912 }
2913
2914 /*
2915 * We must send out an sinval message for the domain, to ensure that any
2916 * dependent plans get rebuilt. Since this command doesn't change the
2917 * domain's pg_type row, that won't happen automatically; do it manually.
2918 */
2919 CacheInvalidateHeapTuple(rel, tup, NULL);
2920
2921 ObjectAddressSet(address, TypeRelationId, domainoid);
2922
2923 /* Clean up */
2925
2926 return address;
2927}
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:273
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#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 2743 of file typecmds.c.

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

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 3032 of file typecmds.c.

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

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

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 4064 of file typecmds.c.

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

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 4113 of file typecmds.c.

4115{
4116 Oid elemOid;
4117
4118 /* check permissions on type */
4119 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
4121
4122 /* don't allow direct alteration of array types */
4123 elemOid = get_element_type(typeOid);
4124 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
4125 {
4126 if (ignoreDependent)
4127 return InvalidOid;
4128 ereport(ERROR,
4129 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4130 errmsg("cannot alter array type %s",
4131 format_type_be(typeOid)),
4132 errhint("You can alter type %s, which will alter the array type as well.",
4133 format_type_be(elemOid))));
4134 }
4135
4136 /* and do the work */
4137 return AlterTypeNamespaceInternal(typeOid, nspOid,
4138 false, /* isImplicitArray */
4139 ignoreDependent, /* ignoreDependent */
4140 true, /* errorOnTableType */
4141 objsMoved);
4142}
#define OidIsValid(objectId)
Definition: c.h:775
int errhint(const char *fmt,...)
Definition: elog.c:1321
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:4165

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 4165 of file typecmds.c.

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

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 3831 of file typecmds.c.

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

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 3956 of file typecmds.c.

3957{
3958 Relation rel;
3959 HeapTuple tup;
3960 Form_pg_type typTup;
3961
3962 rel = table_open(TypeRelationId, RowExclusiveLock);
3963
3964 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3965 if (!HeapTupleIsValid(tup))
3966 elog(ERROR, "cache lookup failed for type %u", typeOid);
3967 typTup = (Form_pg_type) GETSTRUCT(tup);
3968
3969 /*
3970 * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3971 * the pg_class entry properly. That will call back to
3972 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3973 */
3974 if (typTup->typtype == TYPTYPE_COMPOSITE)
3975 ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3976 else
3977 AlterTypeOwnerInternal(typeOid, newOwnerId);
3978
3979 /* Update owner dependency reference */
3980 if (hasDependEntry)
3981 changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3982
3983 InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3984
3985 ReleaseSysCache(tup);
3987}
#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:16040
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3996

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 3996 of file typecmds.c.

3997{
3998 Relation rel;
3999 HeapTuple tup;
4000 Form_pg_type typTup;
4001 Datum repl_val[Natts_pg_type];
4002 bool repl_null[Natts_pg_type];
4003 bool repl_repl[Natts_pg_type];
4004 Acl *newAcl;
4005 Datum aclDatum;
4006 bool isNull;
4007
4008 rel = table_open(TypeRelationId, RowExclusiveLock);
4009
4010 tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
4011 if (!HeapTupleIsValid(tup))
4012 elog(ERROR, "cache lookup failed for type %u", typeOid);
4013 typTup = (Form_pg_type) GETSTRUCT(tup);
4014
4015 memset(repl_null, false, sizeof(repl_null));
4016 memset(repl_repl, false, sizeof(repl_repl));
4017
4018 repl_repl[Anum_pg_type_typowner - 1] = true;
4019 repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
4020
4021 aclDatum = heap_getattr(tup,
4022 Anum_pg_type_typacl,
4023 RelationGetDescr(rel),
4024 &isNull);
4025 /* Null ACLs do not require changes */
4026 if (!isNull)
4027 {
4028 newAcl = aclnewowner(DatumGetAclP(aclDatum),
4029 typTup->typowner, newOwnerId);
4030 repl_repl[Anum_pg_type_typacl - 1] = true;
4031 repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
4032 }
4033
4034 tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
4035 repl_repl);
4036
4037 CatalogTupleUpdate(rel, &tup->t_self, tup);
4038
4039 /* If it has an array type, update that too */
4040 if (OidIsValid(typTup->typarray))
4041 AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
4042
4043 /* If it is a range type, update the associated multirange too */
4044 if (typTup->typtype == TYPTYPE_RANGE)
4045 {
4046 Oid multirange_typeid = get_range_multirange(typeOid);
4047
4048 if (!OidIsValid(multirange_typeid))
4049 ereport(ERROR,
4050 (errcode(ERRCODE_UNDEFINED_OBJECT),
4051 errmsg("could not find multirange type for data type %s",
4052 format_type_be(typeOid))));
4053 AlterTypeOwnerInternal(multirange_typeid, newOwnerId);
4054 }
4055
4056 /* Clean up */
4058}
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 2448 of file typecmds.c.

2449{
2450 Oid type_array_oid;
2451
2452 /* Use binary-upgrade override for pg_type.typarray? */
2453 if (IsBinaryUpgrade)
2454 {
2456 ereport(ERROR,
2457 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2458 errmsg("pg_type array OID value not set when in binary upgrade mode")));
2459
2462 }
2463 else
2464 {
2465 Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2466
2467 type_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2468 Anum_pg_type_oid);
2469 table_close(pg_type, AccessShareLock);
2470 }
2471
2472 return type_array_oid;
2473}
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 2514 of file typecmds.c.

2515{
2516 Oid type_multirange_array_oid;
2517
2518 /* Use binary-upgrade override for pg_type.oid? */
2519 if (IsBinaryUpgrade)
2520 {
2522 ereport(ERROR,
2523 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2524 errmsg("pg_type multirange array OID value not set when in binary upgrade mode")));
2525
2526 type_multirange_array_oid = binary_upgrade_next_mrng_array_pg_type_oid;
2528 }
2529 else
2530 {
2531 Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2532
2533 type_multirange_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2534 Anum_pg_type_oid);
2535 table_close(pg_type, AccessShareLock);
2536 }
2537
2538 return type_multirange_array_oid;
2539}
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 2481 of file typecmds.c.

2482{
2483 Oid type_multirange_oid;
2484
2485 /* Use binary-upgrade override for pg_type.oid? */
2486 if (IsBinaryUpgrade)
2487 {
2489 ereport(ERROR,
2490 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2491 errmsg("pg_type multirange OID value not set when in binary upgrade mode")));
2492
2493 type_multirange_oid = binary_upgrade_next_mrng_pg_type_oid;
2495 }
2496 else
2497 {
2498 Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2499
2500 type_multirange_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2501 Anum_pg_type_oid);
2502 table_close(pg_type, AccessShareLock);
2503 }
2504
2505 return type_multirange_oid;
2506}
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 3495 of file typecmds.c.

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

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 2556 of file typecmds.c.

2557{
2558 CreateStmt *createStmt = makeNode(CreateStmt);
2559 Oid old_type_oid;
2560 Oid typeNamespace;
2561 ObjectAddress address;
2562
2563 /*
2564 * now set the parameters for keys/inheritance etc. All of these are
2565 * uninteresting for composite types...
2566 */
2567 createStmt->relation = typevar;
2568 createStmt->tableElts = coldeflist;
2569 createStmt->inhRelations = NIL;
2570 createStmt->constraints = NIL;
2571 createStmt->options = NIL;
2572 createStmt->oncommit = ONCOMMIT_NOOP;
2573 createStmt->tablespacename = NULL;
2574 createStmt->if_not_exists = false;
2575
2576 /*
2577 * Check for collision with an existing type name. If there is one and
2578 * it's an autogenerated array, we can rename it out of the way. This
2579 * check is here mainly to get a better error message about a "type"
2580 * instead of below about a "relation".
2581 */
2582 typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2583 NoLock, NULL);
2584 RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2585 old_type_oid =
2586 GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
2587 CStringGetDatum(createStmt->relation->relname),
2588 ObjectIdGetDatum(typeNamespace));
2589 if (OidIsValid(old_type_oid))
2590 {
2591 if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2592 ereport(ERROR,
2594 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2595 }
2596
2597 /*
2598 * Finally create the relation. This also creates the type.
2599 */
2600 DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2601 NULL);
2602
2603 return address;
2604}
#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:2750
OnCommitAction oncommit
Definition: parsenodes.h:2759
List * options
Definition: parsenodes.h:2758
bool if_not_exists
Definition: parsenodes.h:2762
List * inhRelations
Definition: parsenodes.h:2751
RangeVar * relation
Definition: parsenodes.h:2749
char * tablespacename
Definition: parsenodes.h:2760
List * constraints
Definition: parsenodes.h:2756
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:765

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:534
int32_t int32
Definition: c.h:535
#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:2813
@ CONSTR_FOREIGN
Definition: parsenodes.h:2808
@ CONSTR_ATTR_DEFERRED
Definition: parsenodes.h:2811
@ CONSTR_IDENTITY
Definition: parsenodes.h:2802
@ CONSTR_UNIQUE
Definition: parsenodes.h:2806
@ CONSTR_ATTR_NOT_DEFERRABLE
Definition: parsenodes.h:2810
@ CONSTR_DEFAULT
Definition: parsenodes.h:2801
@ CONSTR_ATTR_IMMEDIATE
Definition: parsenodes.h:2812
@ CONSTR_NULL
Definition: parsenodes.h:2798
@ CONSTR_GENERATED
Definition: parsenodes.h:2803
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2807
@ CONSTR_ATTR_DEFERRABLE
Definition: parsenodes.h:2809
@ CONSTR_ATTR_NOT_ENFORCED
Definition: parsenodes.h:2814
@ CONSTR_PRIMARY
Definition: parsenodes.h:2805
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:2839
Node * raw_expr
Definition: parsenodes.h:2840
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:2448
void CommandCounterIncrement(void)
Definition: xact.c:1100

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 /* And create the constructor functions for this range type */
1746 makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1747 makeMultirangeConstructors(multirangeTypeName, typeNamespace,
1748 multirangeOid, typoid, rangeArrayOid,
1749 &castFuncOid);
1750
1751 /* Create cast from the range type to its multirange type */
1752 CastCreate(typoid, multirangeOid, castFuncOid, InvalidOid, InvalidOid,
1753 COERCION_CODE_EXPLICIT, COERCION_METHOD_FUNCTION,
1755
1756 pfree(multirangeArrayName);
1757
1758 return address;
1759}
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:223
Oid regproc
Definition: c.h:655
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:2481
static Oid findRangeSubOpclass(List *opcname, Oid subtype)
Definition: typecmds.c:2320
static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype)
Definition: typecmds.c:2400
static void makeMultirangeConstructors(const char *name, Oid namespace, Oid multirangeOid, Oid rangeOid, Oid rangeArrayOid, Oid *castFuncOid)
Definition: typecmds.c:1846
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2359
static void makeRangeConstructors(const char *name, Oid namespace, Oid rangeOid, Oid subtype)
Definition: typecmds.c:1771
Oid AssignTypeMultirangeArrayOid(void)
Definition: typecmds.c:2514

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, Assert(), AssignTypeArrayOid(), AssignTypeMultirangeArrayOid(), AssignTypeMultirangeOid(), CastCreate(), 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:2343
ObjectAddress TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
Definition: pg_type.c:57
ParseLoc location
Definition: parsenodes.h:846
static Oid findTypeOutputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2054
static Oid findTypeInputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1991

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, ItemPointer 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 3750 of file typecmds.c.

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

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