PostgreSQL Source Code git master
Loading...
Searching...
No Matches
typecmds.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/relation.h"
#include "access/table.h"
#include "access/tableam.h"
#include "access/xact.h"
#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
#include "catalog/heap.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_am.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_range.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "commands/tablecmds.h"
#include "commands/typecmds.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for typecmds.c:

Go to the source code of this file.

Data Structures

struct  RelToCheck
 
struct  AlterTypeRecurseParams
 

Functions

static void makeRangeConstructors (const char *name, Oid namespace, Oid rangeOid, Oid subtype, Oid *rangeConstruct2_p, Oid *rangeConstruct3_p)
 
static void makeMultirangeConstructors (const char *name, Oid namespace, Oid multirangeOid, Oid rangeOid, Oid rangeArrayOid, Oid *mltrngConstruct0_p, Oid *mltrngConstruct1_p, Oid *mltrngConstruct2_p)
 
static Oid findTypeInputFunction (List *procname, Oid typeOid)
 
static Oid findTypeOutputFunction (List *procname, Oid typeOid)
 
static Oid findTypeReceiveFunction (List *procname, Oid typeOid)
 
static Oid findTypeSendFunction (List *procname, Oid typeOid)
 
static Oid findTypeTypmodinFunction (List *procname)
 
static Oid findTypeTypmodoutFunction (List *procname)
 
static Oid findTypeAnalyzeFunction (List *procname, Oid typeOid)
 
static Oid findTypeSubscriptingFunction (List *procname, Oid typeOid)
 
static Oid findRangeSubOpclass (List *opcname, Oid subtype)
 
static Oid findRangeCanonicalFunction (List *procname, Oid typeOid)
 
static Oid findRangeSubtypeDiffFunction (List *procname, Oid subtype)
 
static void validateDomainCheckConstraint (Oid domainoid, const char *ccbin)
 
static void validateDomainNotNullConstraint (Oid domainoid)
 
static Listget_rels_with_domain (Oid domainOid, LOCKMODE lockmode)
 
static void checkEnumOwner (HeapTuple tup)
 
static chardomainAddCheckConstraint (Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
 
static Nodereplace_domain_constraint_value (ParseState *pstate, ColumnRef *cref)
 
static void domainAddNotNullConstraint (Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
 
static void AlterTypeRecurse (Oid typeOid, bool isImplicitArray, HeapTuple tup, Relation catalog, AlterTypeRecurseParams *atparams)
 
ObjectAddress DefineType (ParseState *pstate, List *names, List *parameters)
 
void RemoveTypeById (Oid typeOid)
 
ObjectAddress DefineDomain (ParseState *pstate, CreateDomainStmt *stmt)
 
ObjectAddress DefineEnum (CreateEnumStmt *stmt)
 
ObjectAddress AlterEnum (AlterEnumStmt *stmt)
 
ObjectAddress DefineRange (ParseState *pstate, CreateRangeStmt *stmt)
 
Oid AssignTypeArrayOid (void)
 
Oid AssignTypeMultirangeOid (void)
 
Oid AssignTypeMultirangeArrayOid (void)
 
ObjectAddress DefineCompositeType (RangeVar *typevar, List *coldeflist)
 
ObjectAddress AlterDomainDefault (List *names, Node *defaultRaw)
 
ObjectAddress AlterDomainNotNull (List *names, bool notNull)
 
ObjectAddress AlterDomainDropConstraint (List *names, const char *constrName, DropBehavior behavior, bool missing_ok)
 
ObjectAddress AlterDomainAddConstraint (List *names, Node *newConstraint, ObjectAddress *constrAddr)
 
ObjectAddress AlterDomainValidateConstraint (List *names, const char *constrName)
 
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)
 

Variables

Oid binary_upgrade_next_array_pg_type_oid = InvalidOid
 
Oid binary_upgrade_next_mrng_pg_type_oid = InvalidOid
 
Oid binary_upgrade_next_mrng_array_pg_type_oid = InvalidOid
 

Function Documentation

◆ AlterDomainAddConstraint()

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

Definition at line 2966 of file typecmds.c.

2968{
2969 TypeName *typename;
2970 Oid domainoid;
2972 HeapTuple tup;
2974 Constraint *constr;
2975 char *ccbin;
2977
2978 /* Make a TypeName so we can use standard type lookup machinery */
2979 typename = makeTypeNameFromNameList(names);
2980 domainoid = typenameTypeId(NULL, typename);
2981
2982 /* Look up the domain in the type table */
2984
2986 if (!HeapTupleIsValid(tup))
2987 elog(ERROR, "cache lookup failed for type %u", domainoid);
2989
2990 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2992
2994 elog(ERROR, "unrecognized node type: %d",
2995 (int) nodeTag(newConstraint));
2996
2997 constr = (Constraint *) newConstraint;
2998
2999 /* enforced by parser */
3000 Assert(constr->contype == CONSTR_CHECK || constr->contype == CONSTR_NOTNULL);
3001
3002 if (constr->contype == CONSTR_CHECK)
3003 {
3004 /*
3005 * First, process the constraint expression and add an entry to
3006 * pg_constraint.
3007 */
3008
3009 ccbin = domainAddCheckConstraint(domainoid, typTup->typnamespace,
3010 typTup->typbasetype, typTup->typtypmod,
3011 constr, NameStr(typTup->typname), constrAddr);
3012
3013
3014 /*
3015 * If requested to validate the constraint, test all values stored in
3016 * the attributes based on the domain the constraint is being added
3017 * to.
3018 */
3019 if (!constr->skip_validation)
3021
3022 /*
3023 * We must send out an sinval message for the domain, to ensure that
3024 * any dependent plans get rebuilt. Since this command doesn't change
3025 * the domain's pg_type row, that won't happen automatically; do it
3026 * manually.
3027 */
3029 }
3030 else if (constr->contype == CONSTR_NOTNULL)
3031 {
3032 /* Is the domain already set NOT NULL? */
3033 if (typTup->typnotnull)
3034 {
3036 return address;
3037 }
3039 typTup->typbasetype, typTup->typtypmod,
3040 constr, NameStr(typTup->typname), constrAddr);
3041
3042 if (!constr->skip_validation)
3044
3045 typTup->typnotnull = true;
3046 CatalogTupleUpdate(typrel, &tup->t_self, tup);
3047 }
3048
3050
3051 /* Clean up */
3053
3054 return address;
3055}
#define NameStr(name)
Definition c.h:894
#define Assert(condition)
Definition c.h:1002
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition inval.c:1568
#define RowExclusiveLock
Definition lockdefs.h:38
TypeName * makeTypeNameFromNameList(List *names)
Definition makefuncs.c:531
#define IsA(nodeptr, _type_)
Definition nodes.h:162
#define nodeTag(nodeptr)
Definition nodes.h:137
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition parse_type.c:291
@ CONSTR_NOTNULL
@ CONSTR_CHECK
END_CATALOG_STRUCT typedef FormData_pg_type * Form_pg_type
Definition pg_type.h:265
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
unsigned int Oid
static int fb(int x)
ConstrType contype
bool skip_validation
#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 void validateDomainCheckConstraint(Oid domainoid, const char *ccbin)
Definition typecmds.c:3234
static char * domainAddCheckConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition typecmds.c:3545
void checkDomainOwner(HeapTuple tup)
Definition typecmds.c:3525
static void domainAddNotNullConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition typecmds.c:3705
static void validateDomainNotNullConstraint(Oid domainoid)
Definition typecmds.c:3168

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

Referenced by ATExecCmd(), and ProcessUtilitySlow().

◆ AlterDomainDefault()

ObjectAddress AlterDomainDefault ( List names,
Node defaultRaw 
)

Definition at line 2645 of file typecmds.c.

2646{
2647 TypeName *typename;
2648 Oid domainoid;
2649 HeapTuple tup;
2650 ParseState *pstate;
2651 Relation rel;
2652 char *defaultValue;
2653 Node *defaultExpr = NULL; /* NULL if no default specified */
2655 bool new_record_nulls[Natts_pg_type] = {0};
2656 bool new_record_repl[Natts_pg_type] = {0};
2657 HeapTuple newtuple;
2659 ObjectAddress address;
2660
2661 /* Make a TypeName so we can use standard type lookup machinery */
2662 typename = makeTypeNameFromNameList(names);
2663 domainoid = typenameTypeId(NULL, typename);
2664
2665 /* Look up the domain in the type table */
2667
2669 if (!HeapTupleIsValid(tup))
2670 elog(ERROR, "cache lookup failed for type %u", domainoid);
2672
2673 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2675
2676 /* Setup new tuple */
2677
2678 /* Store the new default into the tuple */
2679 if (defaultRaw)
2680 {
2681 /* Create a dummy ParseState for transformExpr */
2682 pstate = make_parsestate(NULL);
2683
2684 /*
2685 * Cook the colDef->raw_expr into an expression. Note: Name is
2686 * strictly for error message
2687 */
2689 typTup->typbasetype,
2690 typTup->typtypmod,
2691 NameStr(typTup->typname),
2692 0);
2693
2694 /*
2695 * If the expression is just a NULL constant, we treat the command
2696 * like ALTER ... DROP DEFAULT. (But see note for same test in
2697 * DefineDomain.)
2698 */
2699 if (defaultExpr == NULL ||
2701 {
2702 /* Default is NULL, drop it */
2703 defaultExpr = NULL;
2708 }
2709 else
2710 {
2711 /*
2712 * Expression must be stored as a nodeToString result, but we also
2713 * require a valid textual representation (mainly to make life
2714 * easier for pg_dump).
2715 */
2717 NIL, false, false);
2718
2719 /*
2720 * Form an updated tuple with the new default and write it back.
2721 */
2723
2727 }
2728 }
2729 else
2730 {
2731 /* ALTER ... DROP DEFAULT */
2736 }
2737
2738 newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2741
2742 CatalogTupleUpdate(rel, &tup->t_self, newtuple);
2743
2744 /* Rebuild dependencies */
2745 GenerateTypeDependencies(newtuple,
2746 rel,
2748 NULL, /* don't have typacl handy */
2749 0, /* relation kind is n/a */
2750 false, /* a domain isn't an implicit array */
2751 false, /* nor is it any kind of dependent type */
2752 false, /* don't touch extension membership */
2753 true); /* We do need to rebuild dependencies */
2754
2756
2758
2759 /* Clean up */
2761 heap_freetuple(newtuple);
2762
2763 return address;
2764}
#define CStringGetTextDatum(s)
Definition builtins.h:98
Node * cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
Definition heap.c:3343
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1118
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
#define InvokeObjectPostAlterHook(classId, objectId, subId)
char * nodeToString(const void *obj)
Definition outfuncs.c:811
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:542
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition ruleutils.c:4009
Definition nodes.h:133

References CatalogTupleUpdate(), checkDomainOwner(), cookDefault(), CStringGetTextDatum, deparse_expression(), elog, ERROR, fb(), Form_pg_type, GenerateTypeDependencies(), GETSTRUCT(), heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, IsA, make_parsestate(), makeTypeNameFromNameList(), NameStr, NIL, nodeToString(), ObjectAddressSet, ObjectIdGetDatum(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, 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 2860 of file typecmds.c.

2862{
2863 TypeName *typename;
2864 Oid domainoid;
2865 HeapTuple tup;
2866 Relation rel;
2869 ScanKeyData skey[3];
2871 bool found = false;
2872 ObjectAddress address;
2873
2874 /* Make a TypeName so we can use standard type lookup machinery */
2875 typename = makeTypeNameFromNameList(names);
2876 domainoid = typenameTypeId(NULL, typename);
2877
2878 /* Look up the domain in the type table */
2880
2882 if (!HeapTupleIsValid(tup))
2883 elog(ERROR, "cache lookup failed for type %u", domainoid);
2884
2885 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2887
2888 /* Grab an appropriate lock on the pg_constraint relation */
2890
2891 /* Find and remove the target constraint */
2892 ScanKeyInit(&skey[0],
2896 ScanKeyInit(&skey[1],
2900 ScanKeyInit(&skey[2],
2904
2906 NULL, 3, skey);
2907
2908 /* There can be at most one matching row */
2909 if ((contup = systable_getnext(conscan)) != NULL)
2910 {
2913
2914 if (construct->contype == CONSTRAINT_NOTNULL)
2915 {
2916 ((Form_pg_type) GETSTRUCT(tup))->typnotnull = false;
2917 CatalogTupleUpdate(rel, &tup->t_self, tup);
2918 }
2919
2920 conobj.classId = ConstraintRelationId;
2921 conobj.objectId = construct->oid;
2922 conobj.objectSubId = 0;
2923
2924 performDeletion(&conobj, behavior, 0);
2925 found = true;
2926 }
2927
2928 /* Clean up after the scan */
2931
2932 if (!found)
2933 {
2934 if (!missing_ok)
2935 ereport(ERROR,
2937 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2938 constrName, TypeNameToString(typename))));
2939 else
2941 (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2942 constrName, TypeNameToString(typename))));
2943 }
2944
2945 /*
2946 * We must send out an sinval message for the domain, to ensure that any
2947 * dependent plans get rebuilt. Since this command doesn't change the
2948 * domain's pg_type row, that won't happen automatically; do it manually.
2949 */
2951
2953
2954 /* Clean up */
2956
2957 return address;
2958}
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition dependency.c:279
int errcode(int sqlerrcode)
Definition elog.c:875
#define NOTICE
Definition elog.h:36
#define ereport(elevel,...)
Definition elog.h:152
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
static char * errmsg
char * TypeNameToString(const TypeName *typeName)
Definition parse_type.c:478
END_CATALOG_STRUCT typedef FormData_pg_constraint * Form_pg_constraint
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
#define InvalidOid
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(), CStringGetDatum(), elog, ereport, errcode(), errmsg, ERROR, fb(), Form_pg_constraint, Form_pg_type, GETSTRUCT(), HeapTupleIsValid, InvalidOid, makeTypeNameFromNameList(), NOTICE, ObjectAddressSet, ObjectIdGetDatum(), performDeletion(), RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TypeNameToString(), and typenameTypeId().

Referenced by ProcessUtilitySlow().

◆ AlterDomainNotNull()

ObjectAddress AlterDomainNotNull ( List names,
bool  notNull 
)

Definition at line 2774 of file typecmds.c.

2775{
2776 TypeName *typename;
2777 Oid domainoid;
2779 HeapTuple tup;
2782
2783 /* Make a TypeName so we can use standard type lookup machinery */
2784 typename = makeTypeNameFromNameList(names);
2785 domainoid = typenameTypeId(NULL, typename);
2786
2787 /* Look up the domain in the type table */
2789
2791 if (!HeapTupleIsValid(tup))
2792 elog(ERROR, "cache lookup failed for type %u", domainoid);
2794
2795 /* Check it's a domain and check user has permission for ALTER DOMAIN */
2797
2798 /* Is the domain already set to the desired constraint? */
2799 if (typTup->typnotnull == notNull)
2800 {
2802 return address;
2803 }
2804
2805 if (notNull)
2806 {
2807 Constraint *constr;
2808
2809 constr = makeNode(Constraint);
2810 constr->contype = CONSTR_NOTNULL;
2811 constr->initially_valid = true;
2812 constr->location = -1;
2813
2815 typTup->typbasetype, typTup->typtypmod,
2816 constr, NameStr(typTup->typname), NULL);
2817
2819 }
2820 else
2821 {
2824
2826 if (conTup == NULL)
2827 elog(ERROR, "could not find not-null constraint on domain \"%s\"", NameStr(typTup->typname));
2828
2831 }
2832
2833 /*
2834 * Okay to update pg_type row. We can scribble on typTup because it's a
2835 * copy.
2836 */
2837 typTup->typnotnull = notNull;
2838
2839 CatalogTupleUpdate(typrel, &tup->t_self, tup);
2840
2842
2844
2845 /* Clean up */
2848
2849 return address;
2850}
#define makeNode(_type_)
Definition nodes.h:159
@ DROP_RESTRICT
HeapTuple findDomainNotNullConstraint(Oid typid)
ParseLoc location
bool initially_valid

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

Referenced by ProcessUtilitySlow().

◆ AlterDomainValidateConstraint()

ObjectAddress AlterDomainValidateConstraint ( List names,
const char constrName 
)

Definition at line 3066 of file typecmds.c.

3067{
3068 TypeName *typename;
3069 Oid domainoid;
3072 HeapTuple tup;
3075 char *conbin;
3076 SysScanDesc scan;
3077 Datum val;
3078 HeapTuple tuple;
3080 ScanKeyData skey[3];
3082
3083 /* Make a TypeName so we can use standard type lookup machinery */
3084 typename = makeTypeNameFromNameList(names);
3085 domainoid = typenameTypeId(NULL, typename);
3086
3087 /* Look up the domain in the type table */
3089
3091 if (!HeapTupleIsValid(tup))
3092 elog(ERROR, "cache lookup failed for type %u", domainoid);
3093
3094 /* Check it's a domain and check user has permission for ALTER DOMAIN */
3096
3097 /*
3098 * Find and check the target constraint
3099 */
3101
3102 ScanKeyInit(&skey[0],
3106 ScanKeyInit(&skey[1],
3110 ScanKeyInit(&skey[2],
3114
3116 NULL, 3, skey);
3117
3118 /* There can be at most one matching row */
3119 if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
3120 ereport(ERROR,
3122 errmsg("constraint \"%s\" of domain \"%s\" does not exist",
3123 constrName, TypeNameToString(typename))));
3124
3125 con = (Form_pg_constraint) GETSTRUCT(tuple);
3126 if (con->contype != CONSTRAINT_CHECK)
3127 ereport(ERROR,
3129 errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
3130 constrName, TypeNameToString(typename))));
3131
3132 if (!con->convalidated)
3133 {
3136
3138
3139 /*
3140 * Now update the catalog, while we have the door open.
3141 */
3142 copyTuple = heap_copytuple(tuple);
3144 copy_con->convalidated = true;
3146
3148
3150
3152 }
3153
3154 systable_endscan(scan);
3155
3158
3160
3161 return address;
3162}
#define TextDatumGetCString(d)
Definition builtins.h:99
HeapTuple heap_copytuple(HeapTuple tuple)
Definition heaptuple.c:686
long val
Definition informix.c:689
#define AccessShareLock
Definition lockdefs.h:36
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
Datum SysCacheGetAttrNotNull(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber)
Definition syscache.c:626
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221

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

Referenced by ProcessUtilitySlow().

◆ AlterEnum()

ObjectAddress AlterEnum ( AlterEnumStmt stmt)

Definition at line 1307 of file typecmds.c.

1308{
1310 TypeName *typename;
1311 HeapTuple tup;
1312 ObjectAddress address;
1313
1314 /* Make a TypeName so we can use standard type lookup machinery */
1315 typename = makeTypeNameFromNameList(stmt->typeName);
1316 enum_type_oid = typenameTypeId(NULL, typename);
1317
1319 if (!HeapTupleIsValid(tup))
1320 elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1321
1322 /* Check it's an enum and check user has permission to ALTER the enum */
1324
1326
1327 if (stmt->oldVal)
1328 {
1329 /* Rename an existing label */
1330 RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
1331 }
1332 else
1333 {
1334 /* Add a new label */
1336 stmt->newValNeighbor, stmt->newValIsAfter,
1337 stmt->skipIfNewValExists);
1338 }
1339
1341
1343
1344 return address;
1345}
#define stmt
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:1355

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

Referenced by ProcessUtilitySlow().

◆ AlterType()

ObjectAddress AlterType ( AlterTypeStmt stmt)

Definition at line 4351 of file typecmds.c.

4352{
4353 ObjectAddress address;
4355 TypeName *typename;
4356 HeapTuple tup;
4357 Oid typeOid;
4359 bool requireSuper = false;
4361 ListCell *pl;
4362
4364
4365 /* Make a TypeName so we can use standard type lookup machinery */
4366 typename = makeTypeNameFromNameList(stmt->typeName);
4367 tup = typenameType(NULL, typename, NULL);
4368
4369 typeOid = typeTypeId(tup);
4371
4372 /* Process options */
4373 memset(&atparams, 0, sizeof(atparams));
4374 foreach(pl, stmt->options)
4375 {
4376 DefElem *defel = (DefElem *) lfirst(pl);
4377
4378 if (strcmp(defel->defname, "storage") == 0)
4379 {
4380 char *a = defGetString(defel);
4381
4382 if (pg_strcasecmp(a, "plain") == 0)
4383 atparams.storage = TYPSTORAGE_PLAIN;
4384 else if (pg_strcasecmp(a, "external") == 0)
4385 atparams.storage = TYPSTORAGE_EXTERNAL;
4386 else if (pg_strcasecmp(a, "extended") == 0)
4387 atparams.storage = TYPSTORAGE_EXTENDED;
4388 else if (pg_strcasecmp(a, "main") == 0)
4389 atparams.storage = TYPSTORAGE_MAIN;
4390 else
4391 ereport(ERROR,
4393 errmsg("storage \"%s\" not recognized", a)));
4394
4395 /*
4396 * Validate the storage request. If the type isn't varlena, it
4397 * certainly doesn't support non-PLAIN storage.
4398 */
4399 if (atparams.storage != TYPSTORAGE_PLAIN && typForm->typlen != -1)
4400 ereport(ERROR,
4402 errmsg("fixed-size types must have storage PLAIN")));
4403
4404 /*
4405 * Switching from PLAIN to non-PLAIN is allowed, but it requires
4406 * superuser, since we can't validate that the type's C functions
4407 * will support it. Switching from non-PLAIN to PLAIN is
4408 * disallowed outright, because it's not practical to ensure that
4409 * no tables have toasted values of the type. Switching among
4410 * different non-PLAIN settings is OK, since it just constitutes a
4411 * change in the strategy requested for columns created in the
4412 * future.
4413 */
4414 if (atparams.storage != TYPSTORAGE_PLAIN &&
4415 typForm->typstorage == TYPSTORAGE_PLAIN)
4416 requireSuper = true;
4417 else if (atparams.storage == TYPSTORAGE_PLAIN &&
4418 typForm->typstorage != TYPSTORAGE_PLAIN)
4419 ereport(ERROR,
4421 errmsg("cannot change type's storage to PLAIN")));
4422
4423 atparams.updateStorage = true;
4424 }
4425 else if (strcmp(defel->defname, "receive") == 0)
4426 {
4427 if (defel->arg != NULL)
4428 atparams.receiveOid =
4430 typeOid);
4431 else
4432 atparams.receiveOid = InvalidOid; /* NONE, remove function */
4433 atparams.updateReceive = true;
4434 /* Replacing an I/O function requires superuser. */
4435 requireSuper = true;
4436 }
4437 else if (strcmp(defel->defname, "send") == 0)
4438 {
4439 if (defel->arg != NULL)
4440 atparams.sendOid =
4442 typeOid);
4443 else
4444 atparams.sendOid = InvalidOid; /* NONE, remove function */
4445 atparams.updateSend = true;
4446 /* Replacing an I/O function requires superuser. */
4447 requireSuper = true;
4448 }
4449 else if (strcmp(defel->defname, "typmod_in") == 0)
4450 {
4451 if (defel->arg != NULL)
4452 atparams.typmodinOid =
4454 else
4455 atparams.typmodinOid = InvalidOid; /* NONE, remove function */
4456 atparams.updateTypmodin = true;
4457 /* Replacing an I/O function requires superuser. */
4458 requireSuper = true;
4459 }
4460 else if (strcmp(defel->defname, "typmod_out") == 0)
4461 {
4462 if (defel->arg != NULL)
4463 atparams.typmodoutOid =
4465 else
4466 atparams.typmodoutOid = InvalidOid; /* NONE, remove function */
4467 atparams.updateTypmodout = true;
4468 /* Replacing an I/O function requires superuser. */
4469 requireSuper = true;
4470 }
4471 else if (strcmp(defel->defname, "analyze") == 0)
4472 {
4473 if (defel->arg != NULL)
4474 atparams.analyzeOid =
4476 typeOid);
4477 else
4478 atparams.analyzeOid = InvalidOid; /* NONE, remove function */
4479 atparams.updateAnalyze = true;
4480 /* Replacing an analyze function requires superuser. */
4481 requireSuper = true;
4482 }
4483 else if (strcmp(defel->defname, "subscript") == 0)
4484 {
4485 if (defel->arg != NULL)
4486 atparams.subscriptOid =
4488 typeOid);
4489 else
4490 atparams.subscriptOid = InvalidOid; /* NONE, remove function */
4491 atparams.updateSubscript = true;
4492 /* Replacing a subscript function requires superuser. */
4493 requireSuper = true;
4494 }
4495
4496 /*
4497 * The rest of the options that CREATE accepts cannot be changed.
4498 * Check for them so that we can give a meaningful error message.
4499 */
4500 else if (strcmp(defel->defname, "input") == 0 ||
4501 strcmp(defel->defname, "output") == 0 ||
4502 strcmp(defel->defname, "internallength") == 0 ||
4503 strcmp(defel->defname, "passedbyvalue") == 0 ||
4504 strcmp(defel->defname, "alignment") == 0 ||
4505 strcmp(defel->defname, "like") == 0 ||
4506 strcmp(defel->defname, "category") == 0 ||
4507 strcmp(defel->defname, "preferred") == 0 ||
4508 strcmp(defel->defname, "default") == 0 ||
4509 strcmp(defel->defname, "element") == 0 ||
4510 strcmp(defel->defname, "delimiter") == 0 ||
4511 strcmp(defel->defname, "collatable") == 0)
4512 ereport(ERROR,
4514 errmsg("type attribute \"%s\" cannot be changed",
4515 defel->defname)));
4516 else
4517 ereport(ERROR,
4519 errmsg("type attribute \"%s\" not recognized",
4520 defel->defname)));
4521 }
4522
4523 /*
4524 * Permissions check. Require superuser if we decided the command
4525 * requires that, else must own the type.
4526 */
4527 if (requireSuper)
4528 {
4529 if (!superuser())
4530 ereport(ERROR,
4532 errmsg("must be superuser to alter a type")));
4533 }
4534 else
4535 {
4536 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
4538 }
4539
4540 /*
4541 * We disallow all forms of ALTER TYPE SET on types that aren't plain base
4542 * types. It would for example be highly unsafe, not to mention
4543 * pointless, to change the send/receive functions for a composite type.
4544 * Moreover, pg_dump has no support for changing these properties on
4545 * non-base types. We might weaken this someday, but not now.
4546 *
4547 * Note: if you weaken this enough to allow composite types, be sure to
4548 * adjust the GenerateTypeDependencies call in AlterTypeRecurse.
4549 */
4550 if (typForm->typtype != TYPTYPE_BASE)
4551 ereport(ERROR,
4553 errmsg("%s is not a base type",
4554 format_type_be(typeOid))));
4555
4556 /*
4557 * For the same reasons, don't allow direct alteration of array types.
4558 */
4560 ereport(ERROR,
4562 errmsg("%s is not a base type",
4563 format_type_be(typeOid))));
4564
4565 /* OK, recursively update this type and any arrays/domains over it */
4566 AlterTypeRecurse(typeOid, false, tup, catalog, &atparams);
4567
4568 /* Clean up */
4570
4572
4573 ObjectAddressSet(address, TypeRelationId, typeOid);
4574
4575 return address;
4576}
@ ACLCHECK_NOT_OWNER
Definition acl.h:186
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4156
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition aclchk.c:2997
char * defGetString(DefElem *def)
Definition define.c:34
List * defGetQualifiedName(DefElem *def)
Definition define.c:238
char * format_type_be(Oid type_oid)
int a
Definition isn.c:73
Oid GetUserId(void)
Definition miscinit.c:470
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)
bool superuser(void)
Definition superuser.c:47
static Oid findTypeReceiveFunction(List *procname, Oid typeOid)
Definition typecmds.c:2120
static void AlterTypeRecurse(Oid typeOid, bool isImplicitArray, HeapTuple tup, Relation catalog, AlterTypeRecurseParams *atparams)
Definition typecmds.c:4602
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid)
Definition typecmds.c:2277
static Oid findTypeSendFunction(List *procname, Oid typeOid)
Definition typecmds.c:2174
static Oid findTypeSubscriptingFunction(List *procname, Oid typeOid)
Definition typecmds.c:2304
static Oid findTypeTypmodoutFunction(List *procname)
Definition typecmds.c:2243
static Oid findTypeTypmodinFunction(List *procname)
Definition typecmds.c:2209

References a, aclcheck_error_type(), ACLCHECK_NOT_OWNER, AlterTypeRecurse(), defGetQualifiedName(), defGetString(), ereport, errcode(), errmsg, ERROR, fb(), findTypeAnalyzeFunction(), findTypeReceiveFunction(), findTypeSendFunction(), findTypeSubscriptingFunction(), findTypeTypmodinFunction(), findTypeTypmodoutFunction(), Form_pg_type, format_type_be(), GETSTRUCT(), GetUserId(), InvalidOid, lfirst, makeTypeNameFromNameList(), object_ownercheck(), ObjectAddressSet, pg_strcasecmp(), ReleaseSysCache(), RowExclusiveLock, stmt, superuser(), table_close(), table_open(), typenameType(), and typeTypeId().

Referenced by ProcessUtilitySlow().

◆ AlterTypeNamespace()

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

Definition at line 4094 of file typecmds.c.

4096{
4097 TypeName *typename;
4098 Oid typeOid;
4099 Oid nspOid;
4100 Oid oldNspOid;
4103
4104 /* Make a TypeName so we can use standard type lookup machinery */
4105 typename = makeTypeNameFromNameList(names);
4106 typeOid = typenameTypeId(NULL, typename);
4107
4108 /* Don't allow ALTER DOMAIN on a non-domain type */
4109 if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
4110 ereport(ERROR,
4112 errmsg("%s is not a domain",
4113 format_type_be(typeOid))));
4114
4115 /* get schema OID and check its permissions */
4116 nspOid = LookupCreationNamespace(newschema);
4117
4121
4122 if (oldschema)
4124
4126
4127 return myself;
4128}
ObjectAddresses * new_object_addresses(void)
void free_object_addresses(ObjectAddresses *addrs)
char get_typtype(Oid typid)
Definition lsyscache.c:2945
Oid LookupCreationNamespace(const char *nspname)
Definition namespace.c:3500
@ OBJECT_DOMAIN
Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, bool ignoreDependent, ObjectAddresses *objsMoved)
Definition typecmds.c:4143

References AlterTypeNamespace_oid(), ereport, errcode(), errmsg, ERROR, fb(), 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 4143 of file typecmds.c.

4145{
4146 Oid elemOid;
4147
4148 /* check permissions on type */
4149 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
4151
4152 /* don't allow direct alteration of array types */
4153 elemOid = get_element_type(typeOid);
4154 if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
4155 {
4156 if (ignoreDependent)
4157 return InvalidOid;
4158 ereport(ERROR,
4160 errmsg("cannot alter array type %s",
4161 format_type_be(typeOid)),
4162 errhint("You can alter type %s, which will alter the array type as well.",
4164 }
4165
4166 /* and do the work */
4167 return AlterTypeNamespaceInternal(typeOid, nspOid,
4168 false, /* isImplicitArray */
4169 ignoreDependent, /* ignoreDependent */
4170 true, /* errorOnTableType */
4171 objsMoved);
4172}
#define OidIsValid(objectId)
Definition c.h:917
int errhint(const char *fmt,...) pg_attribute_printf(1
Oid get_element_type(Oid typid)
Definition lsyscache.c:3075
Oid get_array_type(Oid typid)
Definition lsyscache.c:3103
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition typecmds.c:4195

References aclcheck_error_type(), ACLCHECK_NOT_OWNER, AlterTypeNamespaceInternal(), ereport, errcode(), errhint(), errmsg, ERROR, fb(), 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 4195 of file typecmds.c.

4200{
4201 Relation rel;
4202 HeapTuple tup;
4204 Oid oldNspOid;
4205 Oid arrayOid;
4206 bool isCompositeType;
4208
4209 /*
4210 * Make sure we haven't moved this object previously.
4211 */
4213 thisobj.objectId = typeOid;
4214 thisobj.objectSubId = 0;
4215
4217 return InvalidOid;
4218
4220
4222 if (!HeapTupleIsValid(tup))
4223 elog(ERROR, "cache lookup failed for type %u", typeOid);
4225
4226 oldNspOid = typform->typnamespace;
4227 arrayOid = typform->typarray;
4228
4229 /* If the type is already there, we scan skip these next few checks. */
4230 if (oldNspOid != nspOid)
4231 {
4232 /* common checks on switching namespaces */
4234
4235 /* check for duplicate name (more friendly than unique-index failure) */
4237 NameGetDatum(&typform->typname),
4239 ereport(ERROR,
4241 errmsg("type \"%s\" already exists in schema \"%s\"",
4242 NameStr(typform->typname),
4244 }
4245
4246 /* Detect whether type is a composite type (but not a table rowtype) */
4248 (typform->typtype == TYPTYPE_COMPOSITE &&
4250
4251 /* Enforce not-table-type if requested */
4252 if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType)
4253 {
4254 if (ignoreDependent)
4255 {
4257 return InvalidOid;
4258 }
4259 if (errorOnTableType)
4260 ereport(ERROR,
4262 errmsg("%s is a table's row type",
4263 format_type_be(typeOid)),
4264 /* translator: %s is an SQL ALTER command */
4265 errhint("Use %s instead.", "ALTER TABLE")));
4266 }
4267
4268 if (oldNspOid != nspOid)
4269 {
4270 /* OK, modify the pg_type row */
4271
4272 /* tup is a copy, so we can scribble directly on it */
4273 typform->typnamespace = nspOid;
4274
4275 CatalogTupleUpdate(rel, &tup->t_self, tup);
4276 }
4277
4278 /*
4279 * Composite types have pg_class entries.
4280 *
4281 * We need to modify the pg_class tuple as well to reflect the change of
4282 * schema.
4283 */
4284 if (isCompositeType)
4285 {
4287
4289
4292 false, objsMoved);
4293
4295
4296 /*
4297 * Check for constraints associated with the composite type (we don't
4298 * currently support this, but probably will someday).
4299 */
4301 nspOid, false, objsMoved);
4302 }
4303 else
4304 {
4305 /* If it's a domain, it might have constraints */
4306 if (typform->typtype == TYPTYPE_DOMAIN)
4308 objsMoved);
4309 }
4310
4311 /*
4312 * Update dependency on schema, if any --- a table rowtype has not got
4313 * one, and neither does an implicit array.
4314 */
4315 if (oldNspOid != nspOid &&
4316 (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
4320 elog(ERROR, "could not change schema dependency for type \"%s\"",
4321 format_type_be(typeOid));
4322
4324
4326
4328
4330
4331 /* Recursively alter the associated array type, if any */
4332 if (OidIsValid(arrayOid))
4334 true, /* isImplicitArray */
4335 false, /* ignoreDependent */
4336 true, /* errorOnTableType */
4337 objsMoved);
4338
4339 return oldNspOid;
4340}
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2317
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3682
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition namespace.c:3531
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:470
static Datum NameGetDatum(const NameData *X)
Definition postgres.h:406
#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)

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

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

◆ AlterTypeOwner()

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

Definition at line 3861 of file typecmds.c.

3862{
3863 TypeName *typename;
3864 Oid typeOid;
3865 Relation rel;
3866 HeapTuple tup;
3870 ObjectAddress address;
3871
3873
3874 /* Make a TypeName so we can use standard type lookup machinery */
3875 typename = makeTypeNameFromNameList(names);
3876
3877 /* Use LookupTypeName here so that shell types can be processed */
3878 tup = LookupTypeName(NULL, typename, NULL, false);
3879 if (tup == NULL)
3880 ereport(ERROR,
3882 errmsg("type \"%s\" does not exist",
3883 TypeNameToString(typename))));
3884 typeOid = typeTypeId(tup);
3885
3886 /* Copy the syscache entry so we can scribble on it below */
3889 tup = newtup;
3891
3892 /* Don't allow ALTER DOMAIN on a type */
3893 if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3894 ereport(ERROR,
3896 errmsg("%s is not a domain",
3897 format_type_be(typeOid))));
3898
3899 /*
3900 * If it's a composite type, we need to check that it really is a
3901 * free-standing composite type, and not a table's rowtype. We want people
3902 * to use ALTER TABLE not ALTER TYPE for that case.
3903 */
3904 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3906 ereport(ERROR,
3908 errmsg("%s is a table's row type",
3909 format_type_be(typeOid)),
3910 /* translator: %s is an SQL ALTER command */
3911 errhint("Use %s instead.",
3912 "ALTER TABLE")));
3913
3914 /* don't allow direct alteration of array types, either */
3916 ereport(ERROR,
3918 errmsg("cannot alter array type %s",
3919 format_type_be(typeOid)),
3920 errhint("You can alter type %s, which will alter the array type as well.",
3921 format_type_be(typTup->typelem))));
3922
3923 /* don't allow direct alteration of multirange types, either */
3924 if (typTup->typtype == TYPTYPE_MULTIRANGE)
3925 {
3927
3928 /* We don't expect get_multirange_range to fail, but cope if so */
3929 ereport(ERROR,
3931 errmsg("cannot alter multirange type %s",
3932 format_type_be(typeOid)),
3934 errhint("You can alter type %s, which will alter the multirange type as well.",
3935 format_type_be(rangetype)) : 0));
3936 }
3937
3938 /*
3939 * If the new owner is the same as the existing owner, consider the
3940 * command to have succeeded. This is for dump restoration purposes.
3941 */
3942 if (typTup->typowner != newOwnerId)
3943 {
3944 /* Superusers can always do it */
3945 if (!superuser())
3946 {
3947 /* Otherwise, must be owner of the existing object */
3950
3951 /* Must be able to become new owner */
3953
3954 /* New owner must have CREATE privilege on namespace */
3956 newOwnerId,
3957 ACL_CREATE);
3958 if (aclresult != ACLCHECK_OK)
3960 get_namespace_name(typTup->typnamespace));
3961 }
3962
3963 AlterTypeOwner_oid(typeOid, newOwnerId, true);
3964 }
3965
3966 ObjectAddressSet(address, TypeRelationId, typeOid);
3967
3968 /* Clean up */
3970
3971 return address;
3972}
void check_can_set_role(Oid member, Oid role)
Definition acl.c:5374
AclResult
Definition acl.h:183
@ ACLCHECK_OK
Definition acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3902
Oid get_multirange_range(Oid multirangeOid)
Definition lsyscache.c:3844
Type LookupTypeName(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, bool missing_ok)
Definition parse_type.c:38
@ OBJECT_SCHEMA
#define ACL_CREATE
Definition parsenodes.h:85
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition typecmds.c:3986

References ACL_CREATE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTypeOwner_oid(), check_can_set_role(), ereport, errcode(), errhint(), errmsg, ERROR, fb(), Form_pg_type, 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 3986 of file typecmds.c.

3987{
3988 Relation rel;
3989 HeapTuple tup;
3991
3993
3995 if (!HeapTupleIsValid(tup))
3996 elog(ERROR, "cache lookup failed for type %u", typeOid);
3998
3999 /*
4000 * If it's a composite type, invoke ATExecChangeOwner so that we fix up
4001 * the pg_class entry properly. That will call back to
4002 * AlterTypeOwnerInternal to take care of the pg_type entry(s).
4003 */
4004 if (typTup->typtype == TYPTYPE_COMPOSITE)
4006 else
4008
4009 /* Update owner dependency reference */
4010 if (hasDependEntry)
4012
4014
4017}
#define AccessExclusiveLock
Definition lockdefs.h:43
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition typecmds.c:4026

References AccessExclusiveLock, AlterTypeOwnerInternal(), ATExecChangeOwner(), changeDependencyOnOwner(), elog, ERROR, fb(), Form_pg_type, 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 4026 of file typecmds.c.

4027{
4028 Relation rel;
4029 HeapTuple tup;
4034 Acl *newAcl;
4036 bool isNull;
4037
4039
4041 if (!HeapTupleIsValid(tup))
4042 elog(ERROR, "cache lookup failed for type %u", typeOid);
4044
4045 memset(repl_null, false, sizeof(repl_null));
4046 memset(repl_repl, false, sizeof(repl_repl));
4047
4048 repl_repl[Anum_pg_type_typowner - 1] = true;
4050
4053 RelationGetDescr(rel),
4054 &isNull);
4055 /* Null ACLs do not require changes */
4056 if (!isNull)
4057 {
4059 typTup->typowner, newOwnerId);
4060 repl_repl[Anum_pg_type_typacl - 1] = true;
4062 }
4063
4065 repl_repl);
4066
4067 CatalogTupleUpdate(rel, &tup->t_self, tup);
4068
4069 /* If it has an array type, update that too */
4070 if (OidIsValid(typTup->typarray))
4072
4073 /* If it is a range type, update the associated multirange too */
4074 if (typTup->typtype == TYPTYPE_RANGE)
4075 {
4077
4079 ereport(ERROR,
4081 errmsg("could not find multirange type for data type %s",
4082 format_type_be(typeOid))));
4084 }
4085
4086 /* Clean up */
4088}
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition acl.c:1150
#define DatumGetAclP(X)
Definition acl.h:120
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Oid get_range_multirange(Oid rangeOid)
Definition lsyscache.c:3819
#define PointerGetDatum(X)
Definition postgres.h:354

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

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

◆ AlterTypeRecurse()

static void AlterTypeRecurse ( Oid  typeOid,
bool  isImplicitArray,
HeapTuple  tup,
Relation  catalog,
AlterTypeRecurseParams atparams 
)
static

Definition at line 4602 of file typecmds.c.

4605{
4607 bool nulls[Natts_pg_type];
4608 bool replaces[Natts_pg_type];
4610 SysScanDesc scan;
4611 ScanKeyData key[1];
4613
4614 /* Since this function recurses, it could be driven to stack overflow */
4616
4617 /* Update the current type's tuple */
4618 memset(values, 0, sizeof(values));
4619 memset(nulls, 0, sizeof(nulls));
4620 memset(replaces, 0, sizeof(replaces));
4621
4622 if (atparams->updateStorage)
4623 {
4626 }
4627 if (atparams->updateReceive)
4628 {
4631 }
4632 if (atparams->updateSend)
4633 {
4634 replaces[Anum_pg_type_typsend - 1] = true;
4636 }
4637 if (atparams->updateTypmodin)
4638 {
4639 replaces[Anum_pg_type_typmodin - 1] = true;
4641 }
4642 if (atparams->updateTypmodout)
4643 {
4644 replaces[Anum_pg_type_typmodout - 1] = true;
4646 }
4647 if (atparams->updateAnalyze)
4648 {
4651 }
4652 if (atparams->updateSubscript)
4653 {
4656 }
4657
4659 values, nulls, replaces);
4660
4662
4663 /* Rebuild dependencies for this type */
4665 catalog,
4666 NULL, /* don't have defaultExpr handy */
4667 NULL, /* don't have typacl handy */
4668 0, /* we rejected composite types above */
4669 isImplicitArray, /* it might be an array */
4670 isImplicitArray, /* dependent iff it's array */
4671 false, /* don't touch extension membership */
4672 true);
4673
4675
4676 /*
4677 * Arrays inherit their base type's typmodin and typmodout, but none of
4678 * the other properties we're concerned with here. Recurse to the array
4679 * type if needed.
4680 */
4681 if (!isImplicitArray &&
4682 (atparams->updateTypmodin || atparams->updateTypmodout))
4683 {
4684 Oid arrtypoid = ((Form_pg_type) GETSTRUCT(newtup))->typarray;
4685
4686 if (OidIsValid(arrtypoid))
4687 {
4690
4693 elog(ERROR, "cache lookup failed for type %u", arrtypoid);
4694
4695 memset(&arrparams, 0, sizeof(arrparams));
4696 arrparams.updateTypmodin = atparams->updateTypmodin;
4697 arrparams.updateTypmodout = atparams->updateTypmodout;
4698 arrparams.typmodinOid = atparams->typmodinOid;
4699 arrparams.typmodoutOid = atparams->typmodoutOid;
4700
4702
4704 }
4705 }
4706
4707 /*
4708 * Now we need to recurse to domains. However, some properties are not
4709 * inherited by domains, so clear the update flags for those.
4710 */
4711 atparams->updateReceive = false; /* domains use F_DOMAIN_RECV */
4712 atparams->updateTypmodin = false; /* domains don't have typmods */
4713 atparams->updateTypmodout = false;
4714 atparams->updateSubscript = false; /* domains don't have subscriptors */
4715
4716 /* Skip the scan if nothing remains to be done */
4717 if (!(atparams->updateStorage ||
4718 atparams->updateSend ||
4719 atparams->updateAnalyze))
4720 return;
4721
4722 /* Search pg_type for possible domains over this type */
4723 ScanKeyInit(&key[0],
4726 ObjectIdGetDatum(typeOid));
4727
4728 scan = systable_beginscan(catalog, InvalidOid, false,
4729 NULL, 1, key);
4730
4731 while ((domainTup = systable_getnext(scan)) != NULL)
4732 {
4734
4735 /*
4736 * Shouldn't have a nonzero typbasetype in a non-domain, but let's
4737 * check
4738 */
4739 if (domainForm->typtype != TYPTYPE_DOMAIN)
4740 continue;
4741
4743 }
4744
4745 systable_endscan(scan);
4746}
static Datum values[MAXATTR]
Definition bootstrap.c:190
static Datum CharGetDatum(char X)
Definition postgres.h:132
void check_stack_depth(void)
Definition stack_depth.c:96

References AlterTypeRecurse(), BTEqualStrategyNumber, CatalogTupleUpdate(), CharGetDatum(), check_stack_depth(), elog, ERROR, fb(), Form_pg_type, GenerateTypeDependencies(), GETSTRUCT(), heap_modify_tuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHook, ObjectIdGetDatum(), OidIsValid, RelationGetDescr, ReleaseSysCache(), ScanKeyInit(), SearchSysCache1(), systable_beginscan(), systable_endscan(), systable_getnext(), and values.

Referenced by AlterType(), and AlterTypeRecurse().

◆ AssignTypeArrayOid()

Oid AssignTypeArrayOid ( void  )

Definition at line 2479 of file typecmds.c.

2480{
2482
2483 /* Use binary-upgrade override for pg_type.typarray? */
2484 if (IsBinaryUpgrade)
2485 {
2487 ereport(ERROR,
2489 errmsg("pg_type array OID value not set when in binary upgrade mode")));
2490
2493 }
2494 else
2495 {
2497
2501 }
2502
2503 return type_array_oid;
2504}
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:475
bool IsBinaryUpgrade
Definition globals.c:123
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, fb(), 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 2545 of file typecmds.c.

2546{
2548
2549 /* Use binary-upgrade override for pg_type.oid? */
2550 if (IsBinaryUpgrade)
2551 {
2553 ereport(ERROR,
2555 errmsg("pg_type multirange array OID value not set when in binary upgrade mode")));
2556
2559 }
2560 else
2561 {
2563
2567 }
2568
2570}
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, fb(), GetNewOidWithIndex(), InvalidOid, IsBinaryUpgrade, OidIsValid, table_close(), and table_open().

Referenced by DefineRange().

◆ AssignTypeMultirangeOid()

Oid AssignTypeMultirangeOid ( void  )

Definition at line 2512 of file typecmds.c.

2513{
2515
2516 /* Use binary-upgrade override for pg_type.oid? */
2517 if (IsBinaryUpgrade)
2518 {
2520 ereport(ERROR,
2522 errmsg("pg_type multirange OID value not set when in binary upgrade mode")));
2523
2526 }
2527 else
2528 {
2530
2534 }
2535
2536 return type_multirange_oid;
2537}
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, fb(), GetNewOidWithIndex(), InvalidOid, IsBinaryUpgrade, OidIsValid, table_close(), and table_open().

Referenced by DefineRange().

◆ checkDomainOwner()

void checkDomainOwner ( HeapTuple  tup)

Definition at line 3525 of file typecmds.c.

3526{
3528
3529 /* Check that this is actually a domain */
3530 if (typTup->typtype != TYPTYPE_DOMAIN)
3531 ereport(ERROR,
3533 errmsg("%s is not a domain",
3534 format_type_be(typTup->oid))));
3535
3536 /* Permission check: must own type */
3539}

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

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

◆ checkEnumOwner()

static void checkEnumOwner ( HeapTuple  tup)
static

Definition at line 1355 of file typecmds.c.

1356{
1358
1359 /* Check that this is actually an enum */
1360 if (typTup->typtype != TYPTYPE_ENUM)
1361 ereport(ERROR,
1363 errmsg("%s is not an enum",
1364 format_type_be(typTup->oid))));
1365
1366 /* Permission check: must own type */
1369}

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

Referenced by AlterEnum().

◆ DefineCompositeType()

ObjectAddress DefineCompositeType ( RangeVar typevar,
List coldeflist 
)

Definition at line 2587 of file typecmds.c.

2588{
2589 CreateStmt *createStmt = makeNode(CreateStmt);
2592 ObjectAddress address;
2593
2594 /*
2595 * now set the parameters for keys/inheritance etc. All of these are
2596 * uninteresting for composite types...
2597 */
2598 createStmt->relation = typevar;
2599 createStmt->tableElts = coldeflist;
2600 createStmt->inhRelations = NIL;
2601 createStmt->constraints = NIL;
2602 createStmt->options = NIL;
2603 createStmt->oncommit = ONCOMMIT_NOOP;
2604 createStmt->tablespacename = NULL;
2605 createStmt->if_not_exists = false;
2606
2607 /*
2608 * Check for collision with an existing type name. If there is one and
2609 * it's an autogenerated array, we can rename it out of the way. This
2610 * check is here mainly to get a better error message about a "type"
2611 * instead of below about a "relation".
2612 */
2614 NoLock, NULL);
2616 old_type_oid =
2618 CStringGetDatum(createStmt->relation->relname),
2621 {
2623 ereport(ERROR,
2625 errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2626 }
2627
2628 /*
2629 * Finally create the relation. This also creates the type.
2630 */
2631 DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2632 NULL);
2633
2634 return address;
2635}
#define NoLock
Definition lockdefs.h:34
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition namespace.c:740
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition namespace.c:847
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition pg_type.c:903
@ ONCOMMIT_NOOP
Definition primnodes.h:59
List * tableElts
OnCommitAction oncommit
List * options
bool if_not_exists
List * inhRelations
RangeVar * relation
char * tablespacename
List * constraints
char * relname
Definition primnodes.h:84
#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:818

References CreateStmt::constraints, CStringGetDatum(), DefineRelation(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, fb(), 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 699 of file typecmds.c.

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

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, fb(), Form_pg_type, 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 1183 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

◆ DefineRange()

ObjectAddress DefineRange ( ParseState pstate,
CreateRangeStmt stmt 
)

Definition at line 1382 of file typecmds.c.

1383{
1384 char *typeName;
1386 Oid typoid;
1387 char *rangeArrayName;
1388 char *multirangeTypeName = NULL;
1389 char *multirangeArrayName;
1404 bool subtypbyval;
1405 char subtypalign;
1406 char alignment;
1408 ListCell *lc;
1409 ObjectAddress address;
1417
1418 /* Convert list of names to a name and namespace */
1420 &typeName);
1421
1422 /* Check we have creation rights in target namespace */
1424 if (aclresult != ACLCHECK_OK)
1427
1428 /*
1429 * Look to see if type already exists.
1430 */
1432 CStringGetDatum(typeName),
1434
1435 /*
1436 * If it's not a shell, see if it's an autogenerated array type, and if so
1437 * rename it out of the way.
1438 */
1439 if (OidIsValid(typoid) && get_typisdefined(typoid))
1440 {
1441 if (moveArrayTypeName(typoid, typeName, typeNamespace))
1442 typoid = InvalidOid;
1443 else
1444 ereport(ERROR,
1446 errmsg("type \"%s\" already exists", typeName)));
1447 }
1448
1449 /*
1450 * Unlike DefineType(), we don't insist on a shell type existing first, as
1451 * it's only needed if the user wants to specify a canonical function.
1452 */
1453
1454 /* Extract the parameters from the parameter list */
1455 foreach(lc, stmt->params)
1456 {
1457 DefElem *defel = (DefElem *) lfirst(lc);
1458
1459 if (strcmp(defel->defname, "subtype") == 0)
1460 {
1463 /* we can look up the subtype name immediately */
1465 }
1466 else if (strcmp(defel->defname, "subtype_opclass") == 0)
1467 {
1468 if (rangeSubOpclassName != NIL)
1471 }
1472 else if (strcmp(defel->defname, "collation") == 0)
1473 {
1474 if (rangeCollationName != NIL)
1477 }
1478 else if (strcmp(defel->defname, "canonical") == 0)
1479 {
1480 if (rangeCanonicalName != NIL)
1483 }
1484 else if (strcmp(defel->defname, "subtype_diff") == 0)
1485 {
1489 }
1490 else if (strcmp(defel->defname, "multirange_type_name") == 0)
1491 {
1492 if (multirangeTypeName != NULL)
1494 /* we can look up the subtype name immediately */
1497
1498 /* Check we have creation rights in target namespace */
1501 if (aclresult != ACLCHECK_OK)
1504 }
1505 else
1506 ereport(ERROR,
1508 errmsg("type attribute \"%s\" not recognized",
1509 defel->defname)));
1510 }
1511
1512 /* Must have a subtype */
1514 ereport(ERROR,
1516 errmsg("type attribute \"subtype\" is required")));
1517 /* disallow ranges of pseudotypes */
1519 ereport(ERROR,
1521 errmsg("range subtype cannot be %s",
1523
1524 /* Identify subopclass */
1526
1527 /* Identify collation to use, if any */
1529 {
1530 if (rangeCollationName != NIL)
1532 else
1534 }
1535 else
1536 {
1537 if (rangeCollationName != NIL)
1538 ereport(ERROR,
1540 errmsg("range collation specified but subtype does not support collation")));
1542 }
1543
1544 /* Identify support functions, if provided */
1545 if (rangeCanonicalName != NIL)
1546 {
1547 if (!OidIsValid(typoid))
1548 ereport(ERROR,
1550 errmsg("cannot specify a canonical function without a pre-created shell type"),
1551 errhint("Create the type as a shell type, then create its canonicalization function, then do a full CREATE TYPE.")));
1553 typoid);
1554 }
1555 else
1557
1560 rangeSubtype);
1561 else
1563
1566
1567 /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for ranges */
1569
1570 /* Allocate OID for array type, its multirange, and its multirange array */
1574
1575 /* Create the pg_type entry */
1576 address =
1577 TypeCreate(InvalidOid, /* no predetermined type OID */
1578 typeName, /* type name */
1579 typeNamespace, /* namespace */
1580 InvalidOid, /* relation oid (n/a here) */
1581 0, /* relation kind (ditto) */
1582 GetUserId(), /* owner's ID */
1583 -1, /* internal size (always varlena) */
1584 TYPTYPE_RANGE, /* type-type (range type) */
1585 TYPCATEGORY_RANGE, /* type-category (range type) */
1586 false, /* range types are never preferred */
1587 DEFAULT_TYPDELIM, /* array element delimiter */
1588 F_RANGE_IN, /* input procedure */
1589 F_RANGE_OUT, /* output procedure */
1590 F_RANGE_RECV, /* receive procedure */
1591 F_RANGE_SEND, /* send procedure */
1592 InvalidOid, /* typmodin procedure - none */
1593 InvalidOid, /* typmodout procedure - none */
1594 F_RANGE_TYPANALYZE, /* analyze procedure */
1595 InvalidOid, /* subscript procedure - none */
1596 InvalidOid, /* element type ID - none */
1597 false, /* this is not an array type */
1598 rangeArrayOid, /* array type we are about to create */
1599 InvalidOid, /* base type ID (only for domains) */
1600 NULL, /* never a default type value */
1601 NULL, /* no binary form available either */
1602 false, /* never passed by value */
1603 alignment, /* alignment */
1604 TYPSTORAGE_EXTENDED, /* TOAST strategy (always extended) */
1605 -1, /* typMod (Domains only) */
1606 0, /* Array dimensions of typbasetype */
1607 false, /* Type NOT NULL */
1608 InvalidOid); /* type's collation (ranges never have one) */
1609 Assert(typoid == InvalidOid || typoid == address.objectId);
1610 typoid = address.objectId;
1611
1612 /* Create the multirange that goes with it */
1614 {
1616
1617 /*
1618 * Look to see if multirange type already exists.
1619 */
1623
1624 /*
1625 * If it's not a shell, see if it's an autogenerated array type, and
1626 * if so rename it out of the way.
1627 */
1629 {
1631 ereport(ERROR,
1633 errmsg("type \"%s\" already exists", multirangeTypeName)));
1634 }
1635 }
1636 else
1637 {
1638 /* Generate multirange name automatically */
1641 }
1642
1644 TypeCreate(multirangeOid, /* force assignment of this type OID */
1645 multirangeTypeName, /* type name */
1646 multirangeNamespace, /* namespace */
1647 InvalidOid, /* relation oid (n/a here) */
1648 0, /* relation kind (ditto) */
1649 GetUserId(), /* owner's ID */
1650 -1, /* internal size (always varlena) */
1651 TYPTYPE_MULTIRANGE, /* type-type (multirange type) */
1652 TYPCATEGORY_RANGE, /* type-category (range type) */
1653 false, /* multirange types are never preferred */
1654 DEFAULT_TYPDELIM, /* array element delimiter */
1655 F_MULTIRANGE_IN, /* input procedure */
1656 F_MULTIRANGE_OUT, /* output procedure */
1657 F_MULTIRANGE_RECV, /* receive procedure */
1658 F_MULTIRANGE_SEND, /* send procedure */
1659 InvalidOid, /* typmodin procedure - none */
1660 InvalidOid, /* typmodout procedure - none */
1661 F_MULTIRANGE_TYPANALYZE, /* analyze procedure */
1662 InvalidOid, /* subscript procedure - none */
1663 InvalidOid, /* element type ID - none */
1664 false, /* this is not an array type */
1665 multirangeArrayOid, /* array type we are about to create */
1666 InvalidOid, /* base type ID (only for domains) */
1667 NULL, /* never a default type value */
1668 NULL, /* no binary form available either */
1669 false, /* never passed by value */
1670 alignment, /* alignment */
1671 'x', /* TOAST strategy (always extended) */
1672 -1, /* typMod (Domains only) */
1673 0, /* Array dimensions of typbasetype */
1674 false, /* Type NOT NULL */
1675 InvalidOid); /* type's collation (ranges never have one) */
1676 Assert(multirangeOid == mltrngaddress.objectId);
1677
1678 /*
1679 * Create the array type that goes with it.
1680 */
1682
1683 TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1684 rangeArrayName, /* type name */
1685 typeNamespace, /* namespace */
1686 InvalidOid, /* relation oid (n/a here) */
1687 0, /* relation kind (ditto) */
1688 GetUserId(), /* owner's ID */
1689 -1, /* internal size (always varlena) */
1690 TYPTYPE_BASE, /* type-type (base type) */
1691 TYPCATEGORY_ARRAY, /* type-category (array) */
1692 false, /* array types are never preferred */
1693 DEFAULT_TYPDELIM, /* array element delimiter */
1694 F_ARRAY_IN, /* input procedure */
1695 F_ARRAY_OUT, /* output procedure */
1696 F_ARRAY_RECV, /* receive procedure */
1697 F_ARRAY_SEND, /* send procedure */
1698 InvalidOid, /* typmodin procedure - none */
1699 InvalidOid, /* typmodout procedure - none */
1700 F_ARRAY_TYPANALYZE, /* analyze procedure */
1701 F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1702 typoid, /* element type ID */
1703 true, /* yes this is an array type */
1704 InvalidOid, /* no further array type */
1705 InvalidOid, /* base type ID */
1706 NULL, /* never a default type value */
1707 NULL, /* binary default isn't sent either */
1708 false, /* never passed by value */
1709 alignment, /* alignment - same as range's */
1710 TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
1711 -1, /* typMod (Domains only) */
1712 0, /* Array dimensions of typbasetype */
1713 false, /* Type NOT NULL */
1714 InvalidOid); /* typcollation */
1715
1717
1718 /* Create the multirange's array type */
1719
1721
1722 TypeCreate(multirangeArrayOid, /* force assignment of this type OID */
1723 multirangeArrayName, /* type name */
1724 multirangeNamespace, /* namespace */
1725 InvalidOid, /* relation oid (n/a here) */
1726 0, /* relation kind (ditto) */
1727 GetUserId(), /* owner's ID */
1728 -1, /* internal size (always varlena) */
1729 TYPTYPE_BASE, /* type-type (base type) */
1730 TYPCATEGORY_ARRAY, /* type-category (array) */
1731 false, /* array types are never preferred */
1732 DEFAULT_TYPDELIM, /* array element delimiter */
1733 F_ARRAY_IN, /* input procedure */
1734 F_ARRAY_OUT, /* output procedure */
1735 F_ARRAY_RECV, /* receive procedure */
1736 F_ARRAY_SEND, /* send procedure */
1737 InvalidOid, /* typmodin procedure - none */
1738 InvalidOid, /* typmodout procedure - none */
1739 F_ARRAY_TYPANALYZE, /* analyze procedure */
1740 F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1741 multirangeOid, /* element type ID */
1742 true, /* yes this is an array type */
1743 InvalidOid, /* no further array type */
1744 InvalidOid, /* base type ID */
1745 NULL, /* never a default type value */
1746 NULL, /* binary default isn't sent either */
1747 false, /* never passed by value */
1748 alignment, /* alignment - same as range's */
1749 'x', /* ARRAY is always toastable */
1750 -1, /* typMod (Domains only) */
1751 0, /* Array dimensions of typbasetype */
1752 false, /* Type NOT NULL */
1753 InvalidOid); /* typcollation */
1754
1755 /* Ensure these new types are visible to ProcedureCreate */
1757
1758 /* And create the constructor functions for this range type */
1765
1766 /* Create the entry in pg_range */
1771
1772 /* Create cast from the range type to its multirange type */
1776
1778
1779 return address;
1780}
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:308
Oid regproc
Definition c.h:792
TypeName * defGetTypeName(DefElem *def)
Definition define.c:270
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition define.c:370
@ DEPENDENCY_INTERNAL
Definition dependency.h:35
bool get_typisdefined(Oid typid)
Definition lsyscache.c:2487
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition lsyscache.c:2585
Oid get_typcollation(Oid typid)
Definition lsyscache.c:3372
bool type_is_collatable(Oid typid)
Definition lsyscache.c:3397
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, RegProcedure rangeConstruct2, RegProcedure rangeConstruct3, RegProcedure mltrngConstruct0, RegProcedure mltrngConstruct1, RegProcedure mltrngConstruct2)
Definition pg_range.c:36
char * makeMultirangeTypeName(const char *rangeTypeName, Oid typeNamespace)
Definition pg_type.c:948
Oid AssignTypeMultirangeOid(void)
Definition typecmds.c:2512
static Oid findRangeSubOpclass(List *opcname, Oid subtype)
Definition typecmds.c:2351
static void makeMultirangeConstructors(const char *name, Oid namespace, Oid multirangeOid, Oid rangeOid, Oid rangeArrayOid, Oid *mltrngConstruct0_p, Oid *mltrngConstruct1_p, Oid *mltrngConstruct2_p)
Definition typecmds.c:1875
static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype)
Definition typecmds.c:2431
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid)
Definition typecmds.c:2390
static void makeRangeConstructors(const char *name, Oid namespace, Oid rangeOid, Oid subtype, Oid *rangeConstruct2_p, Oid *rangeConstruct3_p)
Definition typecmds.c:1795
Oid AssignTypeMultirangeArrayOid(void)
Definition typecmds.c:2545

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, Assert, AssignTypeArrayOid(), AssignTypeMultirangeArrayOid(), AssignTypeMultirangeOid(), CastCreate(), CommandCounterIncrement(), CStringGetDatum(), DEFAULT_TYPDELIM, defGetQualifiedName(), defGetTypeName(), DEPENDENCY_INTERNAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg, ERROR, errorConflictingDefElem(), fb(), 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 154 of file typecmds.c.

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

References a, ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, Assert, AssignTypeArrayOid(), CStringGetDatum(), DEFAULT_TYPDELIM, defGetBoolean(), defGetQualifiedName(), defGetString(), defGetTypeLength(), defGetTypeName(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg, ERROR, errorConflictingDefElem(), fb(), findTypeAnalyzeFunction(), findTypeInputFunction(), findTypeOutputFunction(), findTypeReceiveFunction(), findTypeSendFunction(), findTypeSubscriptingFunction(), findTypeTypmodinFunction(), findTypeTypmodoutFunction(), Form_pg_type, format_type_be(), get_namespace_name(), get_typisdefined(), get_typlen(), get_typtype(), GETSTRUCT(), GetSysCacheOid2, GetUserId(), InvalidOid, lfirst, 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().

◆ domainAddCheckConstraint()

static char * domainAddCheckConstraint ( Oid  domainOid,
Oid  domainNamespace,
Oid  baseTypeOid,
int  typMod,
Constraint constr,
const char domainName,
ObjectAddress constrAddr 
)
static

Definition at line 3545 of file typecmds.c.

3548{
3549 Node *expr;
3550 char *ccbin;
3551 ParseState *pstate;
3553 Oid ccoid;
3554
3555 Assert(constr->contype == CONSTR_CHECK);
3556
3557 /*
3558 * Assign or validate constraint name
3559 */
3560 if (constr->conname)
3561 {
3563 domainOid,
3564 constr->conname))
3565 ereport(ERROR,
3567 errmsg("constraint \"%s\" for domain \"%s\" already exists",
3568 constr->conname, domainName)));
3569 }
3570 else
3572 NULL,
3573 "check",
3575 NIL);
3576
3577 /*
3578 * Convert the A_EXPR in raw_expr into an EXPR
3579 */
3580 pstate = make_parsestate(NULL);
3581
3582 /*
3583 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
3584 * the expression. Note that it will appear to have the type of the base
3585 * type, not the domain. This seems correct since within the check
3586 * expression, we should not assume the input value can be considered a
3587 * member of the domain.
3588 */
3590 domVal->typeId = baseTypeOid;
3591 domVal->typeMod = typMod;
3592 domVal->collation = get_typcollation(baseTypeOid);
3593 domVal->location = -1; /* will be set when/if used */
3594
3596 pstate->p_ref_hook_state = domVal;
3597
3598 expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
3599
3600 /*
3601 * Make sure it yields a boolean result.
3602 */
3603 expr = coerce_to_boolean(pstate, expr, "CHECK");
3604
3605 /*
3606 * Fix up collation information.
3607 */
3608 assign_expr_collations(pstate, expr);
3609
3610 /*
3611 * Domains don't allow variables (this is probably dead code now that
3612 * add_missing_from is history, but let's be sure).
3613 */
3614 if (pstate->p_rtable != NIL ||
3615 contain_var_clause(expr))
3616 ereport(ERROR,
3618 errmsg("cannot use table references in domain check constraint")));
3619
3620 /*
3621 * Convert to string form for storage.
3622 */
3623 ccbin = nodeToString(expr);
3624
3625 /*
3626 * Store the constraint in pg_constraint
3627 */
3628 ccoid =
3629 CreateConstraintEntry(constr->conname, /* Constraint Name */
3630 domainNamespace, /* namespace */
3631 CONSTRAINT_CHECK, /* Constraint Type */
3632 false, /* Is Deferrable */
3633 false, /* Is Deferred */
3634 true, /* Is Enforced */
3635 !constr->skip_validation, /* Is Validated */
3636 InvalidOid, /* no parent constraint */
3637 InvalidOid, /* not a relation constraint */
3638 NULL,
3639 0,
3640 0,
3641 domainOid, /* domain constraint */
3642 InvalidOid, /* no associated index */
3643 InvalidOid, /* Foreign key fields */
3644 NULL,
3645 NULL,
3646 NULL,
3647 NULL,
3648 0,
3649 ' ',
3650 ' ',
3651 NULL,
3652 0,
3653 ' ',
3654 NULL, /* not an exclusion constraint */
3655 expr, /* Tree form of check constraint */
3656 ccbin, /* Binary form of check constraint */
3657 true, /* is local */
3658 0, /* inhcount */
3659 false, /* connoinherit */
3660 false, /* conperiod */
3661 false); /* is_internal */
3662 if (constrAddr)
3664
3665 /*
3666 * Return the compiled constraint expression so the calling routine can
3667 * perform any additional required tests.
3668 */
3669 return ccbin;
3670}
Node * coerce_to_boolean(ParseState *pstate, Node *node, const char *constructName)
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition parse_expr.c:121
@ EXPR_KIND_DOMAIN_CHECK
Definition parse_node.h:70
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isEnforced, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int16 conInhCount, bool conNoInherit, bool conPeriod, bool is_internal)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
@ CONSTRAINT_DOMAIN
char * conname
void * p_ref_hook_state
Definition parse_node.h:262
PreParseColumnRefHook p_pre_columnref_hook
Definition parse_node.h:258
List * p_rtable
Definition parse_node.h:215
static Node * replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref)
Definition typecmds.c:3674
bool contain_var_clause(Node *node)
Definition var.c:406

References Assert, assign_expr_collations(), ChooseConstraintName(), coerce_to_boolean(), Constraint::conname, CONSTR_CHECK, CONSTRAINT_DOMAIN, ConstraintNameIsUsed(), contain_var_clause(), Constraint::contype, CreateConstraintEntry(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, EXPR_KIND_DOMAIN_CHECK, fb(), get_typcollation(), InvalidOid, make_parsestate(), makeNode, NIL, nodeToString(), ObjectAddressSet, ParseState::p_pre_columnref_hook, ParseState::p_ref_hook_state, ParseState::p_rtable, Constraint::raw_expr, replace_domain_constraint_value(), Constraint::skip_validation, and transformExpr().

Referenced by AlterDomainAddConstraint(), and DefineDomain().

◆ domainAddNotNullConstraint()

static void domainAddNotNullConstraint ( Oid  domainOid,
Oid  domainNamespace,
Oid  baseTypeOid,
int  typMod,
Constraint constr,
const char domainName,
ObjectAddress constrAddr 
)
static

Definition at line 3705 of file typecmds.c.

3708{
3709 Oid ccoid;
3710
3711 Assert(constr->contype == CONSTR_NOTNULL);
3712
3713 /*
3714 * Assign or validate constraint name
3715 */
3716 if (constr->conname)
3717 {
3719 domainOid,
3720 constr->conname))
3721 ereport(ERROR,
3723 errmsg("constraint \"%s\" for domain \"%s\" already exists",
3724 constr->conname, domainName)));
3725 }
3726 else
3728 NULL,
3729 "not_null",
3731 NIL);
3732
3733 /*
3734 * Store the constraint in pg_constraint
3735 */
3736 ccoid =
3737 CreateConstraintEntry(constr->conname, /* Constraint Name */
3738 domainNamespace, /* namespace */
3739 CONSTRAINT_NOTNULL, /* Constraint Type */
3740 false, /* Is Deferrable */
3741 false, /* Is Deferred */
3742 true, /* Is Enforced */
3743 !constr->skip_validation, /* Is Validated */
3744 InvalidOid, /* no parent constraint */
3745 InvalidOid, /* not a relation constraint */
3746 NULL,
3747 0,
3748 0,
3749 domainOid, /* domain constraint */
3750 InvalidOid, /* no associated index */
3751 InvalidOid, /* Foreign key fields */
3752 NULL,
3753 NULL,
3754 NULL,
3755 NULL,
3756 0,
3757 ' ',
3758 ' ',
3759 NULL,
3760 0,
3761 ' ',
3762 NULL, /* not an exclusion constraint */
3763 NULL,
3764 NULL,
3765 true, /* is local */
3766 0, /* inhcount */
3767 false, /* connoinherit */
3768 false, /* conperiod */
3769 false); /* is_internal */
3770
3771 if (constrAddr)
3773}

References Assert, ChooseConstraintName(), Constraint::conname, CONSTR_NOTNULL, CONSTRAINT_DOMAIN, ConstraintNameIsUsed(), Constraint::contype, CreateConstraintEntry(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg, ERROR, fb(), InvalidOid, NIL, ObjectAddressSet, and Constraint::skip_validation.

Referenced by AlterDomainAddConstraint(), AlterDomainNotNull(), and DefineDomain().

◆ findRangeCanonicalFunction()

static Oid findRangeCanonicalFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2390 of file typecmds.c.

2391{
2392 Oid argList[1];
2393 Oid procOid;
2395
2396 /*
2397 * Range canonical functions must take and return the range type, and must
2398 * be immutable.
2399 */
2400 argList[0] = typeOid;
2401
2402 procOid = LookupFuncName(procname, 1, argList, true);
2403
2404 if (!OidIsValid(procOid))
2405 ereport(ERROR,
2407 errmsg("function %s does not exist",
2408 func_signature_string(procname, 1, NIL, argList))));
2409
2410 if (get_func_rettype(procOid) != typeOid)
2411 ereport(ERROR,
2413 errmsg("range canonical function %s must return range type",
2414 func_signature_string(procname, 1, NIL, argList))));
2415
2417 ereport(ERROR,
2419 errmsg("range canonical function %s must be immutable",
2420 func_signature_string(procname, 1, NIL, argList))));
2421
2422 /* Also, range type's creator must have permission to call function */
2424 if (aclresult != ACLCHECK_OK)
2426
2427 return procOid;
2428}
char func_volatile(Oid funcid)
Definition lsyscache.c:2094
char * get_func_name(Oid funcid)
Definition lsyscache.c:1922
Oid get_func_rettype(Oid funcid)
Definition lsyscache.c:1969
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
#define ACL_EXECUTE
Definition parsenodes.h:83

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, ereport, errcode(), errmsg, ERROR, fb(), func_signature_string(), func_volatile(), get_func_name(), get_func_rettype(), GetUserId(), LookupFuncName(), NIL, object_aclcheck(), OBJECT_FUNCTION, and OidIsValid.

Referenced by DefineRange().

◆ findRangeSubOpclass()

static Oid findRangeSubOpclass ( List opcname,
Oid  subtype 
)
static

Definition at line 2351 of file typecmds.c.

2352{
2353 Oid opcid;
2355
2356 if (opcname != NIL)
2357 {
2359
2360 /*
2361 * Verify that the operator class accepts this datatype. Note we will
2362 * accept binary compatibility.
2363 */
2365 if (!IsBinaryCoercible(subtype, opInputType))
2366 ereport(ERROR,
2368 errmsg("operator class \"%s\" does not accept data type %s",
2370 format_type_be(subtype))));
2371 }
2372 else
2373 {
2375 if (!OidIsValid(opcid))
2376 {
2377 /* We spell the error message identically to ResolveOpClass */
2378 ereport(ERROR,
2380 errmsg("data type %s has no default operator class for access method \"%s\"",
2381 format_type_be(subtype), "btree"),
2382 errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
2383 }
2384 }
2385
2386 return opcid;
2387}
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition indexcmds.c:2381
Oid get_opclass_input_type(Oid opclass)
Definition lsyscache.c:1464
Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
bool IsBinaryCoercible(Oid srctype, Oid targettype)

References ereport, errcode(), errhint(), errmsg, ERROR, fb(), format_type_be(), get_opclass_input_type(), get_opclass_oid(), GetDefaultOpClass(), IsBinaryCoercible(), NameListToString(), NIL, and OidIsValid.

Referenced by DefineRange().

◆ findRangeSubtypeDiffFunction()

static Oid findRangeSubtypeDiffFunction ( List procname,
Oid  subtype 
)
static

Definition at line 2431 of file typecmds.c.

2432{
2433 Oid argList[2];
2434 Oid procOid;
2436
2437 /*
2438 * Range subtype diff functions must take two arguments of the subtype,
2439 * must return float8, and must be immutable.
2440 */
2441 argList[0] = subtype;
2442 argList[1] = subtype;
2443
2444 procOid = LookupFuncName(procname, 2, argList, true);
2445
2446 if (!OidIsValid(procOid))
2447 ereport(ERROR,
2449 errmsg("function %s does not exist",
2450 func_signature_string(procname, 2, NIL, argList))));
2451
2453 ereport(ERROR,
2455 errmsg("range subtype diff function %s must return type %s",
2456 func_signature_string(procname, 2, NIL, argList),
2457 "double precision")));
2458
2460 ereport(ERROR,
2462 errmsg("range subtype diff function %s must be immutable",
2463 func_signature_string(procname, 2, NIL, argList))));
2464
2465 /* Also, range type's creator must have permission to call function */
2467 if (aclresult != ACLCHECK_OK)
2469
2470 return procOid;
2471}

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, ereport, errcode(), errmsg, ERROR, fb(), func_signature_string(), func_volatile(), get_func_name(), get_func_rettype(), GetUserId(), LookupFuncName(), NIL, object_aclcheck(), OBJECT_FUNCTION, and OidIsValid.

Referenced by DefineRange().

◆ findTypeAnalyzeFunction()

static Oid findTypeAnalyzeFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2277 of file typecmds.c.

2278{
2279 Oid argList[1];
2280 Oid procOid;
2281
2282 /*
2283 * Analyze functions always take one INTERNAL argument and return bool.
2284 */
2285 argList[0] = INTERNALOID;
2286
2287 procOid = LookupFuncName(procname, 1, argList, true);
2288 if (!OidIsValid(procOid))
2289 ereport(ERROR,
2291 errmsg("function %s does not exist",
2292 func_signature_string(procname, 1, NIL, argList))));
2293
2295 ereport(ERROR,
2297 errmsg("type analyze function %s must return type %s",
2298 NameListToString(procname), "boolean")));
2299
2300 return procOid;
2301}

References ereport, errcode(), errmsg, ERROR, fb(), func_signature_string(), get_func_rettype(), LookupFuncName(), NameListToString(), NIL, and OidIsValid.

Referenced by AlterType(), and DefineType().

◆ findTypeInputFunction()

static Oid findTypeInputFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2022 of file typecmds.c.

2023{
2024 Oid argList[3];
2025 Oid procOid;
2026 Oid procOid2;
2027
2028 /*
2029 * Input functions can take a single argument of type CSTRING, or three
2030 * arguments (string, typioparam OID, typmod). Whine about ambiguity if
2031 * both forms exist.
2032 */
2033 argList[0] = CSTRINGOID;
2034 argList[1] = OIDOID;
2035 argList[2] = INT4OID;
2036
2037 procOid = LookupFuncName(procname, 1, argList, true);
2038 procOid2 = LookupFuncName(procname, 3, argList, true);
2039 if (OidIsValid(procOid))
2040 {
2041 if (OidIsValid(procOid2))
2042 ereport(ERROR,
2044 errmsg("type input function %s has multiple matches",
2045 NameListToString(procname))));
2046 }
2047 else
2048 {
2049 procOid = procOid2;
2050 /* If not found, reference the 1-argument signature in error msg */
2051 if (!OidIsValid(procOid))
2052 ereport(ERROR,
2054 errmsg("function %s does not exist",
2055 func_signature_string(procname, 1, NIL, argList))));
2056 }
2057
2058 /* Input functions must return the target type. */
2059 if (get_func_rettype(procOid) != typeOid)
2060 ereport(ERROR,
2062 errmsg("type input function %s must return type %s",
2063 NameListToString(procname), format_type_be(typeOid))));
2064
2065 /*
2066 * Print warnings if any of the type's I/O functions are marked volatile.
2067 * There is a general assumption that I/O functions are stable or
2068 * immutable; this allows us for example to mark record_in/record_out
2069 * stable rather than volatile. Ideally we would throw errors not just
2070 * warnings here; but since this check is new as of 9.5, and since the
2071 * volatility marking might be just an error-of-omission and not a true
2072 * indication of how the function behaves, we'll let it pass as a warning
2073 * for now.
2074 */
2078 errmsg("type input function %s should not be volatile",
2079 NameListToString(procname))));
2080
2081 return procOid;
2082}

References ereport, errcode(), errmsg, ERROR, fb(), format_type_be(), func_signature_string(), func_volatile(), get_func_rettype(), LookupFuncName(), NameListToString(), NIL, OidIsValid, and WARNING.

Referenced by DefineType().

◆ findTypeOutputFunction()

static Oid findTypeOutputFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2085 of file typecmds.c.

2086{
2087 Oid argList[1];
2088 Oid procOid;
2089
2090 /*
2091 * Output functions always take a single argument of the type and return
2092 * cstring.
2093 */
2094 argList[0] = typeOid;
2095
2096 procOid = LookupFuncName(procname, 1, argList, true);
2097 if (!OidIsValid(procOid))
2098 ereport(ERROR,
2100 errmsg("function %s does not exist",
2101 func_signature_string(procname, 1, NIL, argList))));
2102
2104 ereport(ERROR,
2106 errmsg("type output function %s must return type %s",
2107 NameListToString(procname), "cstring")));
2108
2109 /* Just a warning for now, per comments in findTypeInputFunction */
2113 errmsg("type output function %s should not be volatile",
2114 NameListToString(procname))));
2115
2116 return procOid;
2117}

References ereport, errcode(), errmsg, ERROR, fb(), func_signature_string(), func_volatile(), get_func_rettype(), LookupFuncName(), NameListToString(), NIL, OidIsValid, and WARNING.

Referenced by DefineType().

◆ findTypeReceiveFunction()

static Oid findTypeReceiveFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2120 of file typecmds.c.

2121{
2122 Oid argList[3];
2123 Oid procOid;
2124 Oid procOid2;
2125
2126 /*
2127 * Receive functions can take a single argument of type INTERNAL, or three
2128 * arguments (internal, typioparam OID, typmod). Whine about ambiguity if
2129 * both forms exist.
2130 */
2131 argList[0] = INTERNALOID;
2132 argList[1] = OIDOID;
2133 argList[2] = INT4OID;
2134
2135 procOid = LookupFuncName(procname, 1, argList, true);
2136 procOid2 = LookupFuncName(procname, 3, argList, true);
2137 if (OidIsValid(procOid))
2138 {
2139 if (OidIsValid(procOid2))
2140 ereport(ERROR,
2142 errmsg("type receive function %s has multiple matches",
2143 NameListToString(procname))));
2144 }
2145 else
2146 {
2147 procOid = procOid2;
2148 /* If not found, reference the 1-argument signature in error msg */
2149 if (!OidIsValid(procOid))
2150 ereport(ERROR,
2152 errmsg("function %s does not exist",
2153 func_signature_string(procname, 1, NIL, argList))));
2154 }
2155
2156 /* Receive functions must return the target type. */
2157 if (get_func_rettype(procOid) != typeOid)
2158 ereport(ERROR,
2160 errmsg("type receive function %s must return type %s",
2161 NameListToString(procname), format_type_be(typeOid))));
2162
2163 /* Just a warning for now, per comments in findTypeInputFunction */
2167 errmsg("type receive function %s should not be volatile",
2168 NameListToString(procname))));
2169
2170 return procOid;
2171}

References ereport, errcode(), errmsg, ERROR, fb(), format_type_be(), func_signature_string(), func_volatile(), get_func_rettype(), LookupFuncName(), NameListToString(), NIL, OidIsValid, and WARNING.

Referenced by AlterType(), and DefineType().

◆ findTypeSendFunction()

static Oid findTypeSendFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2174 of file typecmds.c.

2175{
2176 Oid argList[1];
2177 Oid procOid;
2178
2179 /*
2180 * Send functions always take a single argument of the type and return
2181 * bytea.
2182 */
2183 argList[0] = typeOid;
2184
2185 procOid = LookupFuncName(procname, 1, argList, true);
2186 if (!OidIsValid(procOid))
2187 ereport(ERROR,
2189 errmsg("function %s does not exist",
2190 func_signature_string(procname, 1, NIL, argList))));
2191
2193 ereport(ERROR,
2195 errmsg("type send function %s must return type %s",
2196 NameListToString(procname), "bytea")));
2197
2198 /* Just a warning for now, per comments in findTypeInputFunction */
2202 errmsg("type send function %s should not be volatile",
2203 NameListToString(procname))));
2204
2205 return procOid;
2206}

References ereport, errcode(), errmsg, ERROR, fb(), func_signature_string(), func_volatile(), get_func_rettype(), LookupFuncName(), NameListToString(), NIL, OidIsValid, and WARNING.

Referenced by AlterType(), and DefineType().

◆ findTypeSubscriptingFunction()

static Oid findTypeSubscriptingFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2304 of file typecmds.c.

2305{
2306 Oid argList[1];
2307 Oid procOid;
2308
2309 /*
2310 * Subscripting support functions always take one INTERNAL argument and
2311 * return INTERNAL. (The argument is not used, but we must have it to
2312 * maintain type safety.)
2313 */
2314 argList[0] = INTERNALOID;
2315
2316 procOid = LookupFuncName(procname, 1, argList, true);
2317 if (!OidIsValid(procOid))
2318 ereport(ERROR,
2320 errmsg("function %s does not exist",
2321 func_signature_string(procname, 1, NIL, argList))));
2322
2324 ereport(ERROR,
2326 errmsg("type subscripting function %s must return type %s",
2327 NameListToString(procname), "internal")));
2328
2329 /*
2330 * We disallow array_subscript_handler() from being selected explicitly,
2331 * since that must only be applied to autogenerated array types.
2332 */
2334 ereport(ERROR,
2336 errmsg("user-defined types cannot use subscripting function %s",
2337 NameListToString(procname))));
2338
2339 return procOid;
2340}

References ereport, errcode(), errmsg, ERROR, fb(), func_signature_string(), get_func_rettype(), LookupFuncName(), NameListToString(), NIL, and OidIsValid.

Referenced by AlterType(), and DefineType().

◆ findTypeTypmodinFunction()

static Oid findTypeTypmodinFunction ( List procname)
static

Definition at line 2209 of file typecmds.c.

2210{
2211 Oid argList[1];
2212 Oid procOid;
2213
2214 /*
2215 * typmodin functions always take one cstring[] argument and return int4.
2216 */
2218
2219 procOid = LookupFuncName(procname, 1, argList, true);
2220 if (!OidIsValid(procOid))
2221 ereport(ERROR,
2223 errmsg("function %s does not exist",
2224 func_signature_string(procname, 1, NIL, argList))));
2225
2227 ereport(ERROR,
2229 errmsg("typmod_in function %s must return type %s",
2230 NameListToString(procname), "integer")));
2231
2232 /* Just a warning for now, per comments in findTypeInputFunction */
2236 errmsg("type modifier input function %s should not be volatile",
2237 NameListToString(procname))));
2238
2239 return procOid;
2240}

References ereport, errcode(), errmsg, ERROR, fb(), func_signature_string(), func_volatile(), get_func_rettype(), LookupFuncName(), NameListToString(), NIL, OidIsValid, and WARNING.

Referenced by AlterType(), and DefineType().

◆ findTypeTypmodoutFunction()

static Oid findTypeTypmodoutFunction ( List procname)
static

Definition at line 2243 of file typecmds.c.

2244{
2245 Oid argList[1];
2246 Oid procOid;
2247
2248 /*
2249 * typmodout functions always take one int4 argument and return cstring.
2250 */
2251 argList[0] = INT4OID;
2252
2253 procOid = LookupFuncName(procname, 1, argList, true);
2254 if (!OidIsValid(procOid))
2255 ereport(ERROR,
2257 errmsg("function %s does not exist",
2258 func_signature_string(procname, 1, NIL, argList))));
2259
2261 ereport(ERROR,
2263 errmsg("typmod_out function %s must return type %s",
2264 NameListToString(procname), "cstring")));
2265
2266 /* Just a warning for now, per comments in findTypeInputFunction */
2270 errmsg("type modifier output function %s should not be volatile",
2271 NameListToString(procname))));
2272
2273 return procOid;
2274}

References ereport, errcode(), errmsg, ERROR, fb(), func_signature_string(), func_volatile(), get_func_rettype(), LookupFuncName(), NameListToString(), NIL, OidIsValid, and WARNING.

Referenced by AlterType(), and DefineType().

◆ get_rels_with_domain()

static List * get_rels_with_domain ( Oid  domainOid,
LOCKMODE  lockmode 
)
static

Definition at line 3356 of file typecmds.c.

3357{
3358 List *result = NIL;
3361 ScanKeyData key[2];
3364
3365 Assert(lockmode != NoLock);
3366
3367 /* since this function recurses, it could be driven to stack overflow */
3369
3370 /*
3371 * We scan pg_depend to find those things that depend on the domain. (We
3372 * assume we can ignore refobjsubid for a domain.)
3373 */
3375
3376 ScanKeyInit(&key[0],
3380 ScanKeyInit(&key[1],
3384
3386 NULL, 2, key);
3387
3389 {
3391 RelToCheck *rtc = NULL;
3394 int ptr;
3395
3396 /* Check for directly dependent types */
3397 if (pg_depend->classid == TypeRelationId)
3398 {
3399 if (get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN)
3400 {
3401 /*
3402 * This is a sub-domain, so recursively add dependent columns
3403 * to the output list. This is a bit inefficient since we may
3404 * fail to combine RelToCheck entries when attributes of the
3405 * same rel have different derived domain types, but it's
3406 * probably not worth improving.
3407 */
3410 lockmode));
3411 }
3412 else
3413 {
3414 /*
3415 * Otherwise, it is some container type using the domain, so
3416 * fail if there are any columns of this type.
3417 */
3419 NULL,
3421 }
3422 continue;
3423 }
3424
3425 /* Else, ignore dependees that aren't user columns of relations */
3426 /* (we assume system columns are never of domain types) */
3427 if (pg_depend->classid != RelationRelationId ||
3428 pg_depend->objsubid <= 0)
3429 continue;
3430
3431 /* See if we already have an entry for this relation */
3432 foreach(rellist, result)
3433 {
3435
3436 if (RelationGetRelid(rt->rel) == pg_depend->objid)
3437 {
3438 rtc = rt;
3439 break;
3440 }
3441 }
3442
3443 if (rtc == NULL)
3444 {
3445 /* First attribute found for this relation */
3446 Relation rel;
3447
3448 /* Acquire requested lock on relation */
3449 rel = relation_open(pg_depend->objid, lockmode);
3450
3451 /*
3452 * Check to see if rowtype is stored anyplace as a composite-type
3453 * column; if so we have to fail, for now anyway.
3454 */
3455 if (OidIsValid(rel->rd_rel->reltype))
3457 NULL,
3459
3460 /*
3461 * Otherwise, we can ignore relations except those with both
3462 * storage and user-chosen column types.
3463 *
3464 * XXX If an index-only scan could satisfy "col::some_domain" from
3465 * a suitable expression index, this should also check expression
3466 * index columns.
3467 */
3468 if (rel->rd_rel->relkind != RELKIND_RELATION &&
3469 rel->rd_rel->relkind != RELKIND_MATVIEW)
3470 {
3471 relation_close(rel, lockmode);
3472 continue;
3473 }
3474
3475 /* Build the RelToCheck entry with enough space for all atts */
3477 rtc->rel = rel;
3478 rtc->natts = 0;
3481 }
3482
3483 /*
3484 * Confirm column has not been dropped, and is of the expected type.
3485 * This defends against an ALTER DROP COLUMN occurring just before we
3486 * acquired lock ... but if the whole table were dropped, we'd still
3487 * have a problem.
3488 */
3489 if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
3490 continue;
3491 pg_att = TupleDescAttr(rtc->rel->rd_att, pg_depend->objsubid - 1);
3492 if (pg_att->attisdropped || pg_att->atttypid != domainOid)
3493 continue;
3494
3495 /*
3496 * Okay, add column to result. We store the columns in column-number
3497 * order; this is just a hack to improve predictability of regression
3498 * test output ...
3499 */
3501
3502 ptr = rtc->natts++;
3503 while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
3504 {
3505 rtc->atts[ptr] = rtc->atts[ptr - 1];
3506 ptr--;
3507 }
3508 rtc->atts[ptr] = pg_depend->objsubid;
3509 }
3510
3512
3514
3515 return result;
3516}
uint32 result
#define palloc_object(type)
Definition fe_memutils.h:89
#define palloc_array(type, count)
Definition fe_memutils.h:91
List * lappend(List *list, void *datum)
Definition list.c:339
List * list_concat(List *list1, const List *list2)
Definition list.c:561
FormData_pg_attribute * Form_pg_attribute
END_CATALOG_STRUCT typedef FormData_pg_depend * Form_pg_depend
Definition pg_depend.h:76
#define RelationGetRelid(relation)
Definition rel.h:516
#define RelationGetNumberOfAttributes(relation)
Definition rel.h:522
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:48
Form_pg_class rd_rel
Definition rel.h:111
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition tablecmds.c:7077
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
static List * get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
Definition typecmds.c:3356

References AccessShareLock, Assert, BTEqualStrategyNumber, check_stack_depth(), fb(), find_composite_type_dependencies(), Form_pg_depend, format_type_be(), get_rels_with_domain(), get_typtype(), GETSTRUCT(), HeapTupleIsValid, lappend(), lfirst, list_concat(), NIL, NoLock, ObjectIdGetDatum(), OidIsValid, palloc_array, palloc_object, RelationData::rd_rel, relation_close(), relation_open(), RelationGetNumberOfAttributes, RelationGetRelid, result, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_open(), and TupleDescAttr().

Referenced by get_rels_with_domain(), validateDomainCheckConstraint(), and validateDomainNotNullConstraint().

◆ makeMultirangeConstructors()

static void makeMultirangeConstructors ( const char name,
Oid  namespace,
Oid  multirangeOid,
Oid  rangeOid,
Oid  rangeArrayOid,
Oid mltrngConstruct0_p,
Oid mltrngConstruct1_p,
Oid mltrngConstruct2_p 
)
static

Definition at line 1875 of file typecmds.c.

1878{
1880 referenced;
1881 oidvector *argtypes;
1886
1887 referenced.classId = TypeRelationId;
1888 referenced.objectId = multirangeOid;
1889 referenced.objectSubId = 0;
1890
1891 /* 0-arg constructor - for empty multiranges */
1892 argtypes = buildoidvector(NULL, 0);
1893 myself = ProcedureCreate(name, /* name: same as multirange type */
1894 namespace,
1895 false, /* replace */
1896 false, /* returns set */
1897 multirangeOid, /* return type */
1898 BOOTSTRAP_SUPERUSERID, /* proowner */
1899 INTERNALlanguageId, /* language */
1901 "multirange_constructor0", /* prosrc */
1902 NULL, /* probin */
1903 NULL, /* prosqlbody */
1905 false, /* security_definer */
1906 false, /* leakproof */
1907 true, /* isStrict */
1908 PROVOLATILE_IMMUTABLE, /* volatility */
1909 PROPARALLEL_SAFE, /* parallel safety */
1910 argtypes, /* parameterTypes */
1911 PointerGetDatum(NULL), /* allParameterTypes */
1912 PointerGetDatum(NULL), /* parameterModes */
1913 PointerGetDatum(NULL), /* parameterNames */
1914 NIL, /* parameterDefaults */
1915 PointerGetDatum(NULL), /* trftypes */
1916 NIL, /* trfoids */
1917 PointerGetDatum(NULL), /* proconfig */
1918 InvalidOid, /* prosupport */
1919 1.0, /* procost */
1920 0.0); /* prorows */
1921
1922 /*
1923 * Make the constructor internally-dependent on the multirange type so
1924 * that they go away silently when the type is dropped. Note that pg_dump
1925 * depends on this choice to avoid dumping the constructors.
1926 */
1928 *mltrngConstruct0_p = myself.objectId;
1929 pfree(argtypes);
1930
1931 /*
1932 * 1-arg constructor - for casts
1933 *
1934 * In theory we shouldn't need both this and the vararg (n-arg)
1935 * constructor, but having a separate 1-arg function lets us define casts
1936 * against it.
1937 */
1938 argtypes = buildoidvector(&rangeOid, 1);
1939 myself = ProcedureCreate(name, /* name: same as multirange type */
1940 namespace,
1941 false, /* replace */
1942 false, /* returns set */
1943 multirangeOid, /* return type */
1944 BOOTSTRAP_SUPERUSERID, /* proowner */
1945 INTERNALlanguageId, /* language */
1947 "multirange_constructor1", /* prosrc */
1948 NULL, /* probin */
1949 NULL, /* prosqlbody */
1951 false, /* security_definer */
1952 false, /* leakproof */
1953 true, /* isStrict */
1954 PROVOLATILE_IMMUTABLE, /* volatility */
1955 PROPARALLEL_SAFE, /* parallel safety */
1956 argtypes, /* parameterTypes */
1957 PointerGetDatum(NULL), /* allParameterTypes */
1958 PointerGetDatum(NULL), /* parameterModes */
1959 PointerGetDatum(NULL), /* parameterNames */
1960 NIL, /* parameterDefaults */
1961 PointerGetDatum(NULL), /* trftypes */
1962 NIL, /* trfoids */
1963 PointerGetDatum(NULL), /* proconfig */
1964 InvalidOid, /* prosupport */
1965 1.0, /* procost */
1966 0.0); /* prorows */
1967 /* ditto */
1969 *mltrngConstruct1_p = myself.objectId;
1970 pfree(argtypes);
1971
1972 /* n-arg constructor - vararg */
1973 argtypes = buildoidvector(&rangeArrayOid, 1);
1978 myself = ProcedureCreate(name, /* name: same as multirange type */
1979 namespace,
1980 false, /* replace */
1981 false, /* returns set */
1982 multirangeOid, /* return type */
1983 BOOTSTRAP_SUPERUSERID, /* proowner */
1984 INTERNALlanguageId, /* language */
1986 "multirange_constructor2", /* prosrc */
1987 NULL, /* probin */
1988 NULL, /* prosqlbody */
1990 false, /* security_definer */
1991 false, /* leakproof */
1992 true, /* isStrict */
1993 PROVOLATILE_IMMUTABLE, /* volatility */
1994 PROPARALLEL_SAFE, /* parallel safety */
1995 argtypes, /* parameterTypes */
1996 PointerGetDatum(allParameterTypes), /* allParameterTypes */
1997 PointerGetDatum(parameterModes), /* parameterModes */
1998 PointerGetDatum(NULL), /* parameterNames */
1999 NIL, /* parameterDefaults */
2000 PointerGetDatum(NULL), /* trftypes */
2001 NIL, /* trfoids */
2002 PointerGetDatum(NULL), /* proconfig */
2003 InvalidOid, /* prosupport */
2004 1.0, /* procost */
2005 0.0); /* prorows */
2006 /* ditto */
2008 *mltrngConstruct2_p = myself.objectId;
2009 pfree(argtypes);
2012}
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
oidvector * buildoidvector(const Oid *oids, int n)
Definition oid.c:87
@ FUNC_PARAM_VARIADIC
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition pg_depend.c:51
ObjectAddress ProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, Node *prosqlbody, char prokind, bool security_definer, bool isLeakProof, bool isStrict, char volatility, char parallel, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Datum trftypes, List *trfoids, Datum proconfig, Oid prosupport, float4 procost, float4 prorows)
Definition pg_proc.c:99
Definition c.h:874
const char * name

References buildoidvector(), CharGetDatum(), construct_array_builtin(), DEPENDENCY_INTERNAL, fb(), FUNC_PARAM_VARIADIC, InvalidOid, name, NIL, ObjectIdGetDatum(), pfree(), PointerGetDatum, ProcedureCreate(), and recordDependencyOn().

Referenced by DefineRange().

◆ makeRangeConstructors()

static void makeRangeConstructors ( const char name,
Oid  namespace,
Oid  rangeOid,
Oid  subtype,
Oid rangeConstruct2_p,
Oid rangeConstruct3_p 
)
static

Definition at line 1795 of file typecmds.c.

1798{
1799 static const char *const prosrc[2] = {"range_constructor2",
1800 "range_constructor3"};
1801 static const int pronargs[2] = {2, 3};
1802
1805 referenced;
1806
1807 constructorArgTypes[0] = subtype;
1808 constructorArgTypes[1] = subtype;
1810
1812 referenced.objectId = rangeOid;
1813 referenced.objectSubId = 0;
1814
1815 for (size_t i = 0; i < lengthof(prosrc); i++)
1816 {
1818
1820 pronargs[i]);
1821
1822 myself = ProcedureCreate(name, /* name: same as range type */
1823 namespace, /* namespace */
1824 false, /* replace */
1825 false, /* returns set */
1826 rangeOid, /* return type */
1827 BOOTSTRAP_SUPERUSERID, /* proowner */
1828 INTERNALlanguageId, /* language */
1829 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1830 prosrc[i], /* prosrc */
1831 NULL, /* probin */
1832 NULL, /* prosqlbody */
1834 false, /* security_definer */
1835 false, /* leakproof */
1836 false, /* isStrict */
1837 PROVOLATILE_IMMUTABLE, /* volatility */
1838 PROPARALLEL_SAFE, /* parallel safety */
1839 constructorArgTypesVector, /* parameterTypes */
1840 PointerGetDatum(NULL), /* allParameterTypes */
1841 PointerGetDatum(NULL), /* parameterModes */
1842 PointerGetDatum(NULL), /* parameterNames */
1843 NIL, /* parameterDefaults */
1844 PointerGetDatum(NULL), /* trftypes */
1845 NIL, /* trfoids */
1846 PointerGetDatum(NULL), /* proconfig */
1847 InvalidOid, /* prosupport */
1848 1.0, /* procost */
1849 0.0); /* prorows */
1850
1851 /*
1852 * Make the constructors internally-dependent on the range type so
1853 * that they go away silently when the type is dropped. Note that
1854 * pg_dump depends on this choice to avoid dumping the constructors.
1855 */
1857
1858 if (pronargs[i] == 2)
1859 *rangeConstruct2_p = myself.objectId;
1860 else if (pronargs[i] == 3)
1861 *rangeConstruct3_p = myself.objectId;
1862 }
1863}
#define lengthof(array)
Definition c.h:932
int i
Definition isn.c:77
int16 pronargs
Definition pg_proc.h:83

References buildoidvector(), ObjectAddress::classId, DEPENDENCY_INTERNAL, fb(), i, InvalidOid, lengthof, name, NIL, PointerGetDatum, ProcedureCreate(), pronargs, and recordDependencyOn().

Referenced by DefineRange().

◆ RemoveTypeById()

void RemoveTypeById ( Oid  typeOid)

Definition at line 659 of file typecmds.c.

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

References CatalogTupleDelete(), elog, EnumValuesDelete(), ERROR, fb(), Form_pg_type, GETSTRUCT(), HeapTupleIsValid, ObjectIdGetDatum(), RangeDelete(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), table_close(), and table_open().

Referenced by doDeletion().

◆ RenameType()

ObjectAddress RenameType ( RenameStmt stmt)

Definition at line 3780 of file typecmds.c.

3781{
3782 List *names = castNode(List, stmt->object);
3783 const char *newTypeName = stmt->newname;
3784 TypeName *typename;
3785 Oid typeOid;
3786 Relation rel;
3787 HeapTuple tup;
3789 ObjectAddress address;
3790
3791 /* Make a TypeName so we can use standard type lookup machinery */
3792 typename = makeTypeNameFromNameList(names);
3793 typeOid = typenameTypeId(NULL, typename);
3794
3795 /* Look up the type in the type table */
3797
3799 if (!HeapTupleIsValid(tup))
3800 elog(ERROR, "cache lookup failed for type %u", typeOid);
3802
3803 /* check permissions on type */
3804 if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
3806
3807 /* ALTER DOMAIN used on a non-domain? */
3808 if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3809 ereport(ERROR,
3811 errmsg("%s is not a domain",
3812 format_type_be(typeOid))));
3813
3814 /*
3815 * If it's a composite type, we need to check that it really is a
3816 * free-standing composite type, and not a table's rowtype. We want people
3817 * to use ALTER TABLE not ALTER TYPE for that case.
3818 */
3819 if (typTup->typtype == TYPTYPE_COMPOSITE &&
3821 ereport(ERROR,
3823 errmsg("%s is a table's row type",
3824 format_type_be(typeOid)),
3825 /* translator: %s is an SQL ALTER command */
3826 errhint("Use %s instead.",
3827 "ALTER TABLE")));
3828
3829 /* don't allow direct alteration of array types, either */
3831 ereport(ERROR,
3833 errmsg("cannot alter array type %s",
3834 format_type_be(typeOid)),
3835 errhint("You can alter type %s, which will alter the array type as well.",
3836 format_type_be(typTup->typelem))));
3837
3838 /* we do allow separate renaming of multirange types, though */
3839
3840 /*
3841 * If type is composite we need to rename associated pg_class entry too.
3842 * RenameRelationInternal will call RenameTypeInternal automatically.
3843 */
3844 if (typTup->typtype == TYPTYPE_COMPOSITE)
3845 RenameRelationInternal(typTup->typrelid, newTypeName, false, false);
3846 else
3848 typTup->typnamespace);
3849
3850 ObjectAddressSet(address, TypeRelationId, typeOid);
3851 /* Clean up */
3853
3854 return address;
3855}
#define castNode(_type_, nodeptr)
Definition nodes.h:180
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:4362

References aclcheck_error_type(), ACLCHECK_NOT_OWNER, castNode, elog, ereport, errcode(), errhint(), errmsg, ERROR, fb(), Form_pg_type, 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().

◆ replace_domain_constraint_value()

static Node * replace_domain_constraint_value ( ParseState pstate,
ColumnRef cref 
)
static

Definition at line 3674 of file typecmds.c.

3675{
3676 /*
3677 * Check for a reference to "value", and if that's what it is, replace
3678 * with a CoerceToDomainValue as prepared for us by
3679 * domainAddCheckConstraint. (We handle VALUE as a name, not a keyword, to
3680 * avoid breaking a lot of applications that have used VALUE as a column
3681 * name in the past.)
3682 */
3683 if (list_length(cref->fields) == 1)
3684 {
3685 Node *field1 = (Node *) linitial(cref->fields);
3686 char *colname;
3687
3688 colname = strVal(field1);
3689 if (strcmp(colname, "value") == 0)
3690 {
3692
3693 /* Propagate location knowledge, if any */
3694 domVal->location = cref->location;
3695 return (Node *) domVal;
3696 }
3697 }
3698 return NULL;
3699}
#define copyObject(obj)
Definition nodes.h:230
#define linitial(l)
Definition pg_list.h:178
#define strVal(v)
Definition value.h:82

References copyObject, fb(), linitial, list_length(), ParseState::p_ref_hook_state, and strVal.

Referenced by domainAddCheckConstraint().

◆ validateDomainCheckConstraint()

static void validateDomainCheckConstraint ( Oid  domainoid,
const char ccbin 
)
static

Definition at line 3234 of file typecmds.c.

3235{
3236 Expr *expr = (Expr *) stringToNode(ccbin);
3237 List *rels;
3238 ListCell *rt;
3239 EState *estate;
3240 ExprContext *econtext;
3241 ExprState *exprstate;
3242
3243 /* Need an EState to run ExecEvalExpr */
3244 estate = CreateExecutorState();
3245 econtext = GetPerTupleExprContext(estate);
3246
3247 /* build execution state for expr */
3248 exprstate = ExecPrepareExpr(expr, estate);
3249
3250 /* Fetch relation list with attributes based on this domain */
3251 /* ShareLock is sufficient to prevent concurrent data changes */
3252
3254
3255 foreach(rt, rels)
3256 {
3258 Relation testrel = rtc->rel;
3260 TupleTableSlot *slot;
3261 TableScanDesc scan;
3262 Snapshot snapshot;
3263
3264 /* Scan all tuples in this relation */
3265 snapshot = RegisterSnapshot(GetLatestSnapshot());
3266 scan = table_beginscan(testrel, snapshot, 0, NULL,
3267 SO_NONE);
3269 while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3270 {
3271 int i;
3272
3273 /* Test attributes that are of the domain */
3274 for (i = 0; i < rtc->natts; i++)
3275 {
3276 int attnum = rtc->atts[i];
3277 Datum d;
3278 bool isNull;
3280
3281 d = slot_getattr(slot, attnum, &isNull);
3282
3283 econtext->domainValue_datum = d;
3284 econtext->domainValue_isNull = isNull;
3285
3287 econtext,
3288 &isNull);
3289
3290 if (!isNull && !DatumGetBool(conResult))
3291 {
3292 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
3293
3294 /*
3295 * In principle the auxiliary information for this error
3296 * should be errdomainconstraint(), but errtablecol()
3297 * seems considerably more useful in practice. Since this
3298 * code only executes in an ALTER DOMAIN command, the
3299 * client should already know which domain is in question,
3300 * and which constraint too.
3301 */
3302 ereport(ERROR,
3304 errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
3305 NameStr(attr->attname),
3308 }
3309 }
3310
3311 ResetExprContext(econtext);
3312 }
3314 table_endscan(scan);
3315 UnregisterSnapshot(snapshot);
3316
3317 /* Hold relation lock till commit (XXX bad for concurrency) */
3319 }
3320
3321 FreeExecutorState(estate);
3322}
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition execExpr.c:765
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
void FreeExecutorState(EState *estate)
Definition execUtils.c:197
EState * CreateExecutorState(void)
Definition execUtils.c:90
#define GetPerTupleExprContext(estate)
Definition executor.h:665
#define ResetExprContext(econtext)
Definition executor.h:659
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:444
#define ShareLock
Definition lockdefs.h:40
int16 attnum
static bool DatumGetBool(Datum X)
Definition postgres.h:100
void * stringToNode(const char *str)
Definition read.c:90
#define RelationGetRelationName(relation)
Definition rel.h:550
int errtablecol(Relation rel, int attnum)
Definition relcache.c:6101
@ ForwardScanDirection
Definition sdir.h:28
Snapshot GetLatestSnapshot(void)
Definition snapmgr.c:354
void UnregisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:866
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:824
Datum domainValue_datum
Definition execnodes.h:318
bool domainValue_isNull
Definition execnodes.h:320
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition tableam.c:92
@ SO_NONE
Definition tableam.h:49
static void table_endscan(TableScanDesc scan)
Definition tableam.h:1061
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, ScanKeyData *key, uint32 flags)
Definition tableam.h:943
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition tableam.h:1096
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition tuptable.h:417

References attnum, CreateExecutorState(), DatumGetBool(), ExprContext::domainValue_datum, ExprContext::domainValue_isNull, ereport, errcode(), errmsg, ERROR, errtablecol(), ExecDropSingleTupleTableSlot(), ExecEvalExprSwitchContext(), ExecPrepareExpr(), fb(), ForwardScanDirection, FreeExecutorState(), get_rels_with_domain(), GetLatestSnapshot(), GetPerTupleExprContext, i, lfirst, NameStr, NoLock, RegisterSnapshot(), RelationGetDescr, RelationGetRelationName, ResetExprContext, ShareLock, slot_getattr(), SO_NONE, stringToNode(), table_beginscan(), table_close(), table_endscan(), table_scan_getnextslot(), table_slot_create(), TupleDescAttr(), and UnregisterSnapshot().

Referenced by AlterDomainAddConstraint(), and AlterDomainValidateConstraint().

◆ validateDomainNotNullConstraint()

static void validateDomainNotNullConstraint ( Oid  domainoid)
static

Definition at line 3168 of file typecmds.c.

3169{
3170 List *rels;
3171 ListCell *rt;
3172
3173 /* Fetch relation list with attributes based on this domain */
3174 /* ShareLock is sufficient to prevent concurrent data changes */
3175
3177
3178 foreach(rt, rels)
3179 {
3181 Relation testrel = rtc->rel;
3183 TupleTableSlot *slot;
3184 TableScanDesc scan;
3185 Snapshot snapshot;
3186
3187 /* Scan all tuples in this relation */
3188 snapshot = RegisterSnapshot(GetLatestSnapshot());
3189 scan = table_beginscan(testrel, snapshot, 0, NULL,
3190 SO_NONE);
3192 while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3193 {
3194 int i;
3195
3196 /* Test attributes that are of the domain */
3197 for (i = 0; i < rtc->natts; i++)
3198 {
3199 int attnum = rtc->atts[i];
3200 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
3201
3202 if (slot_attisnull(slot, attnum))
3203 {
3204 /*
3205 * In principle the auxiliary information for this error
3206 * should be errdatatype(), but errtablecol() seems
3207 * considerably more useful in practice. Since this code
3208 * only executes in an ALTER DOMAIN command, the client
3209 * should already know which domain is in question.
3210 */
3211 ereport(ERROR,
3213 errmsg("column \"%s\" of table \"%s\" contains null values",
3214 NameStr(attr->attname),
3217 }
3218 }
3219 }
3221 table_endscan(scan);
3222 UnregisterSnapshot(snapshot);
3223
3224 /* Close each rel after processing, but keep lock */
3226 }
3227}
static bool slot_attisnull(TupleTableSlot *slot, int attnum)
Definition tuptable.h:403

References attnum, ereport, errcode(), errmsg, ERROR, errtablecol(), ExecDropSingleTupleTableSlot(), fb(), ForwardScanDirection, get_rels_with_domain(), GetLatestSnapshot(), i, lfirst, NameStr, NoLock, RegisterSnapshot(), RelationGetDescr, RelationGetRelationName, ShareLock, slot_attisnull(), SO_NONE, table_beginscan(), table_close(), table_endscan(), table_scan_getnextslot(), table_slot_create(), TupleDescAttr(), and UnregisterSnapshot().

Referenced by AlterDomainAddConstraint(), and AlterDomainNotNull().

Variable Documentation

◆ binary_upgrade_next_array_pg_type_oid

Oid binary_upgrade_next_array_pg_type_oid = InvalidOid

Definition at line 109 of file typecmds.c.

Referenced by AssignTypeArrayOid(), and binary_upgrade_set_next_array_pg_type_oid().

◆ binary_upgrade_next_mrng_array_pg_type_oid

Oid binary_upgrade_next_mrng_array_pg_type_oid = InvalidOid

◆ binary_upgrade_next_mrng_pg_type_oid

Oid binary_upgrade_next_mrng_pg_type_oid = InvalidOid