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

Go to the source code of this file.

Macros

#define DEFAULT_TYPDELIM   ','
 

Functions

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

Macro Definition Documentation

◆ DEFAULT_TYPDELIM

#define DEFAULT_TYPDELIM   ','

Definition at line 22 of file typecmds.h.

Function Documentation

◆ AlterDomainAddConstraint()

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

Definition at line 2897 of file typecmds.c.

2899 {
2900  TypeName *typename;
2901  Oid domainoid;
2902  Relation typrel;
2903  HeapTuple tup;
2904  Form_pg_type typTup;
2905  Constraint *constr;
2906  char *ccbin;
2908 
2909  /* Make a TypeName so we can use standard type lookup machinery */
2910  typename = makeTypeNameFromNameList(names);
2911  domainoid = typenameTypeId(NULL, typename);
2912 
2913  /* Look up the domain in the type table */
2914  typrel = table_open(TypeRelationId, RowExclusiveLock);
2915 
2916  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2917  if (!HeapTupleIsValid(tup))
2918  elog(ERROR, "cache lookup failed for type %u", domainoid);
2919  typTup = (Form_pg_type) GETSTRUCT(tup);
2920 
2921  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2922  checkDomainOwner(tup);
2923 
2924  if (!IsA(newConstraint, Constraint))
2925  elog(ERROR, "unrecognized node type: %d",
2926  (int) nodeTag(newConstraint));
2927 
2928  constr = (Constraint *) newConstraint;
2929 
2930  switch (constr->contype)
2931  {
2932  case CONSTR_CHECK:
2933  case CONSTR_NOTNULL:
2934  /* processed below */
2935  break;
2936 
2937  case CONSTR_UNIQUE:
2938  ereport(ERROR,
2939  (errcode(ERRCODE_SYNTAX_ERROR),
2940  errmsg("unique constraints not possible for domains")));
2941  break;
2942 
2943  case CONSTR_PRIMARY:
2944  ereport(ERROR,
2945  (errcode(ERRCODE_SYNTAX_ERROR),
2946  errmsg("primary key constraints not possible for domains")));
2947  break;
2948 
2949  case CONSTR_EXCLUSION:
2950  ereport(ERROR,
2951  (errcode(ERRCODE_SYNTAX_ERROR),
2952  errmsg("exclusion constraints not possible for domains")));
2953  break;
2954 
2955  case CONSTR_FOREIGN:
2956  ereport(ERROR,
2957  (errcode(ERRCODE_SYNTAX_ERROR),
2958  errmsg("foreign key constraints not possible for domains")));
2959  break;
2960 
2963  case CONSTR_ATTR_DEFERRED:
2964  case CONSTR_ATTR_IMMEDIATE:
2965  ereport(ERROR,
2966  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2967  errmsg("specifying constraint deferrability not supported for domains")));
2968  break;
2969 
2970  default:
2971  elog(ERROR, "unrecognized constraint subtype: %d",
2972  (int) constr->contype);
2973  break;
2974  }
2975 
2976  if (constr->contype == CONSTR_CHECK)
2977  {
2978  /*
2979  * First, process the constraint expression and add an entry to
2980  * pg_constraint.
2981  */
2982 
2983  ccbin = domainAddCheckConstraint(domainoid, typTup->typnamespace,
2984  typTup->typbasetype, typTup->typtypmod,
2985  constr, NameStr(typTup->typname), constrAddr);
2986 
2987 
2988  /*
2989  * If requested to validate the constraint, test all values stored in
2990  * the attributes based on the domain the constraint is being added
2991  * to.
2992  */
2993  if (!constr->skip_validation)
2994  validateDomainCheckConstraint(domainoid, ccbin);
2995 
2996  /*
2997  * We must send out an sinval message for the domain, to ensure that
2998  * any dependent plans get rebuilt. Since this command doesn't change
2999  * the domain's pg_type row, that won't happen automatically; do it
3000  * manually.
3001  */
3002  CacheInvalidateHeapTuple(typrel, tup, NULL);
3003  }
3004  else if (constr->contype == CONSTR_NOTNULL)
3005  {
3006  /* Is the domain already set NOT NULL? */
3007  if (typTup->typnotnull)
3008  {
3009  table_close(typrel, RowExclusiveLock);
3010  return address;
3011  }
3012  domainAddNotNullConstraint(domainoid, typTup->typnamespace,
3013  typTup->typbasetype, typTup->typtypmod,
3014  constr, NameStr(typTup->typname), constrAddr);
3015 
3016  if (!constr->skip_validation)
3018 
3019  typTup->typnotnull = true;
3020  CatalogTupleUpdate(typrel, &tup->t_self, tup);
3021  }
3022 
3023  ObjectAddressSet(address, TypeRelationId, domainoid);
3024 
3025  /* Clean up */
3026  table_close(typrel, RowExclusiveLock);
3027 
3028  return address;
3029 }
#define NameStr(name)
Definition: c.h:746
int errcode(int sqlerrcode)
Definition: elog.c:857
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1204
#define RowExclusiveLock
Definition: lockdefs.h:38
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:458
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define nodeTag(nodeptr)
Definition: nodes.h:133
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
@ CONSTR_FOREIGN
Definition: parsenodes.h:2714
@ CONSTR_ATTR_DEFERRED
Definition: parsenodes.h:2717
@ CONSTR_UNIQUE
Definition: parsenodes.h:2712
@ CONSTR_ATTR_NOT_DEFERRABLE
Definition: parsenodes.h:2716
@ CONSTR_NOTNULL
Definition: parsenodes.h:2706
@ CONSTR_ATTR_IMMEDIATE
Definition: parsenodes.h:2718
@ CONSTR_CHECK
Definition: parsenodes.h:2710
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2713
@ CONSTR_ATTR_DEFERRABLE
Definition: parsenodes.h:2715
@ CONSTR_PRIMARY
Definition: parsenodes.h:2711
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
ConstrType contype
Definition: parsenodes.h:2736
bool skip_validation
Definition: parsenodes.h:2740
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
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:3201
static char * domainAddCheckConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:3510
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3490
static void domainAddNotNullConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:3668
static void validateDomainNotNullConstraint(Oid domainoid)
Definition: typecmds.c:3136

References CacheInvalidateHeapTuple(), CatalogTupleUpdate(), checkDomainOwner(), CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_CHECK, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_NOTNULL, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, domainAddCheckConstraint(), domainAddNotNullConstraint(), elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, InvalidObjectAddress, IsA, makeTypeNameFromNameList(), NameStr, nodeTag, ObjectAddressSet, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheCopy1, Constraint::skip_validation, HeapTupleData::t_self, table_close(), table_open(), typenameTypeId(), validateDomainCheckConstraint(), and validateDomainNotNullConstraint().

Referenced by ATExecCmd(), and ProcessUtilitySlow().

◆ AlterDomainDefault()

ObjectAddress AlterDomainDefault ( List names,
Node defaultRaw 
)

Definition at line 2576 of file typecmds.c.

2577 {
2578  TypeName *typename;
2579  Oid domainoid;
2580  HeapTuple tup;
2581  ParseState *pstate;
2582  Relation rel;
2583  char *defaultValue;
2584  Node *defaultExpr = NULL; /* NULL if no default specified */
2585  Datum new_record[Natts_pg_type] = {0};
2586  bool new_record_nulls[Natts_pg_type] = {0};
2587  bool new_record_repl[Natts_pg_type] = {0};
2588  HeapTuple newtuple;
2589  Form_pg_type typTup;
2590  ObjectAddress address;
2591 
2592  /* Make a TypeName so we can use standard type lookup machinery */
2593  typename = makeTypeNameFromNameList(names);
2594  domainoid = typenameTypeId(NULL, typename);
2595 
2596  /* Look up the domain in the type table */
2597  rel = table_open(TypeRelationId, RowExclusiveLock);
2598 
2599  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2600  if (!HeapTupleIsValid(tup))
2601  elog(ERROR, "cache lookup failed for type %u", domainoid);
2602  typTup = (Form_pg_type) GETSTRUCT(tup);
2603 
2604  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2605  checkDomainOwner(tup);
2606 
2607  /* Setup new tuple */
2608 
2609  /* Store the new default into the tuple */
2610  if (defaultRaw)
2611  {
2612  /* Create a dummy ParseState for transformExpr */
2613  pstate = make_parsestate(NULL);
2614 
2615  /*
2616  * Cook the colDef->raw_expr into an expression. Note: Name is
2617  * strictly for error message
2618  */
2619  defaultExpr = cookDefault(pstate, defaultRaw,
2620  typTup->typbasetype,
2621  typTup->typtypmod,
2622  NameStr(typTup->typname),
2623  0);
2624 
2625  /*
2626  * If the expression is just a NULL constant, we treat the command
2627  * like ALTER ... DROP DEFAULT. (But see note for same test in
2628  * DefineDomain.)
2629  */
2630  if (defaultExpr == NULL ||
2631  (IsA(defaultExpr, Const) && ((Const *) defaultExpr)->constisnull))
2632  {
2633  /* Default is NULL, drop it */
2634  defaultExpr = NULL;
2635  new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2636  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2637  new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2638  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2639  }
2640  else
2641  {
2642  /*
2643  * Expression must be stored as a nodeToString result, but we also
2644  * require a valid textual representation (mainly to make life
2645  * easier for pg_dump).
2646  */
2647  defaultValue = deparse_expression(defaultExpr,
2648  NIL, false, false);
2649 
2650  /*
2651  * Form an updated tuple with the new default and write it back.
2652  */
2653  new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2654 
2655  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2656  new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2657  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2658  }
2659  }
2660  else
2661  {
2662  /* ALTER ... DROP DEFAULT */
2663  new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2664  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2665  new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2666  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2667  }
2668 
2669  newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2670  new_record, new_record_nulls,
2671  new_record_repl);
2672 
2673  CatalogTupleUpdate(rel, &tup->t_self, newtuple);
2674 
2675  /* Rebuild dependencies */
2676  GenerateTypeDependencies(newtuple,
2677  rel,
2678  defaultExpr,
2679  NULL, /* don't have typacl handy */
2680  0, /* relation kind is n/a */
2681  false, /* a domain isn't an implicit array */
2682  false, /* nor is it any kind of dependent type */
2683  false, /* don't touch extension membership */
2684  true); /* We do need to rebuild dependencies */
2685 
2686  InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2687 
2688  ObjectAddressSet(address, TypeRelationId, domainoid);
2689 
2690  /* Clean up */
2692  heap_freetuple(newtuple);
2693 
2694  return address;
2695 }
#define CStringGetTextDatum(s)
Definition: builtins.h:97
Node * cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
Definition: heap.c:2747
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
char * nodeToString(const void *obj)
Definition: outfuncs.c:791
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:557
uintptr_t Datum
Definition: postgres.h:64
#define RelationGetDescr(relation)
Definition: rel.h:531
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3598
Definition: nodes.h:129

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

Referenced by ProcessUtilitySlow().

◆ AlterDomainDropConstraint()

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

Definition at line 2791 of file typecmds.c.

2793 {
2794  TypeName *typename;
2795  Oid domainoid;
2796  HeapTuple tup;
2797  Relation rel;
2798  Relation conrel;
2799  SysScanDesc conscan;
2800  ScanKeyData skey[3];
2801  HeapTuple contup;
2802  bool found = false;
2803  ObjectAddress address;
2804 
2805  /* Make a TypeName so we can use standard type lookup machinery */
2806  typename = makeTypeNameFromNameList(names);
2807  domainoid = typenameTypeId(NULL, typename);
2808 
2809  /* Look up the domain in the type table */
2810  rel = table_open(TypeRelationId, RowExclusiveLock);
2811 
2812  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2813  if (!HeapTupleIsValid(tup))
2814  elog(ERROR, "cache lookup failed for type %u", domainoid);
2815 
2816  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2817  checkDomainOwner(tup);
2818 
2819  /* Grab an appropriate lock on the pg_constraint relation */
2820  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
2821 
2822  /* Find and remove the target constraint */
2823  ScanKeyInit(&skey[0],
2824  Anum_pg_constraint_conrelid,
2825  BTEqualStrategyNumber, F_OIDEQ,
2827  ScanKeyInit(&skey[1],
2828  Anum_pg_constraint_contypid,
2829  BTEqualStrategyNumber, F_OIDEQ,
2830  ObjectIdGetDatum(domainoid));
2831  ScanKeyInit(&skey[2],
2832  Anum_pg_constraint_conname,
2833  BTEqualStrategyNumber, F_NAMEEQ,
2834  CStringGetDatum(constrName));
2835 
2836  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
2837  NULL, 3, skey);
2838 
2839  /* There can be at most one matching row */
2840  if ((contup = systable_getnext(conscan)) != NULL)
2841  {
2842  Form_pg_constraint construct = (Form_pg_constraint) GETSTRUCT(contup);
2843  ObjectAddress conobj;
2844 
2845  if (construct->contype == CONSTRAINT_NOTNULL)
2846  {
2847  ((Form_pg_type) GETSTRUCT(tup))->typnotnull = false;
2848  CatalogTupleUpdate(rel, &tup->t_self, tup);
2849  }
2850 
2851  conobj.classId = ConstraintRelationId;
2852  conobj.objectId = construct->oid;
2853  conobj.objectSubId = 0;
2854 
2855  performDeletion(&conobj, behavior, 0);
2856  found = true;
2857  }
2858 
2859  /* Clean up after the scan */
2860  systable_endscan(conscan);
2861  table_close(conrel, RowExclusiveLock);
2862 
2863  if (!found)
2864  {
2865  if (!missing_ok)
2866  ereport(ERROR,
2867  (errcode(ERRCODE_UNDEFINED_OBJECT),
2868  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2869  constrName, TypeNameToString(typename))));
2870  else
2871  ereport(NOTICE,
2872  (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2873  constrName, TypeNameToString(typename))));
2874  }
2875 
2876  /*
2877  * We must send out an sinval message for the domain, to ensure that any
2878  * dependent plans get rebuilt. Since this command doesn't change the
2879  * domain's pg_type row, that won't happen automatically; do it manually.
2880  */
2881  CacheInvalidateHeapTuple(rel, tup, NULL);
2882 
2883  ObjectAddressSet(address, TypeRelationId, domainoid);
2884 
2885  /* Clean up */
2887 
2888  return address;
2889 }
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:273
#define NOTICE
Definition: elog.h:35
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:478
FormData_pg_constraint * Form_pg_constraint
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
#define InvalidOid
Definition: postgres_ext.h:36
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31

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

Referenced by ProcessUtilitySlow().

◆ AlterDomainNotNull()

ObjectAddress AlterDomainNotNull ( List names,
bool  notNull 
)

Definition at line 2705 of file typecmds.c.

2706 {
2707  TypeName *typename;
2708  Oid domainoid;
2709  Relation typrel;
2710  HeapTuple tup;
2711  Form_pg_type typTup;
2713 
2714  /* Make a TypeName so we can use standard type lookup machinery */
2715  typename = makeTypeNameFromNameList(names);
2716  domainoid = typenameTypeId(NULL, typename);
2717 
2718  /* Look up the domain in the type table */
2719  typrel = table_open(TypeRelationId, RowExclusiveLock);
2720 
2721  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2722  if (!HeapTupleIsValid(tup))
2723  elog(ERROR, "cache lookup failed for type %u", domainoid);
2724  typTup = (Form_pg_type) GETSTRUCT(tup);
2725 
2726  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2727  checkDomainOwner(tup);
2728 
2729  /* Is the domain already set to the desired constraint? */
2730  if (typTup->typnotnull == notNull)
2731  {
2732  table_close(typrel, RowExclusiveLock);
2733  return address;
2734  }
2735 
2736  if (notNull)
2737  {
2738  Constraint *constr;
2739 
2740  constr = makeNode(Constraint);
2741  constr->contype = CONSTR_NOTNULL;
2742  constr->initially_valid = true;
2743  constr->location = -1;
2744 
2745  domainAddNotNullConstraint(domainoid, typTup->typnamespace,
2746  typTup->typbasetype, typTup->typtypmod,
2747  constr, NameStr(typTup->typname), NULL);
2748 
2750  }
2751  else
2752  {
2753  HeapTuple conTup;
2754  ObjectAddress conobj;
2755 
2756  conTup = findDomainNotNullConstraint(domainoid);
2757  if (conTup == NULL)
2758  elog(ERROR, "could not find not-null constraint on domain \"%s\"", NameStr(typTup->typname));
2759 
2760  ObjectAddressSet(conobj, ConstraintRelationId, ((Form_pg_constraint) GETSTRUCT(conTup))->oid);
2761  performDeletion(&conobj, DROP_RESTRICT, 0);
2762  }
2763 
2764  /*
2765  * Okay to update pg_type row. We can scribble on typTup because it's a
2766  * copy.
2767  */
2768  typTup->typnotnull = notNull;
2769 
2770  CatalogTupleUpdate(typrel, &tup->t_self, tup);
2771 
2772  InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2773 
2774  ObjectAddressSet(address, TypeRelationId, domainoid);
2775 
2776  /* Clean up */
2777  heap_freetuple(tup);
2778  table_close(typrel, RowExclusiveLock);
2779 
2780  return address;
2781 }
#define makeNode(_type_)
Definition: nodes.h:155
@ DROP_RESTRICT
Definition: parsenodes.h:2334
HeapTuple findDomainNotNullConstraint(Oid typid)
ParseLoc location
Definition: parsenodes.h:2777
bool initially_valid
Definition: parsenodes.h:2741

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

Referenced by ProcessUtilitySlow().

◆ AlterDomainValidateConstraint()

ObjectAddress AlterDomainValidateConstraint ( List names,
const char *  constrName 
)

Definition at line 3037 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterEnum()

ObjectAddress AlterEnum ( AlterEnumStmt stmt)

Definition at line 1271 of file typecmds.c.

1272 {
1273  Oid enum_type_oid;
1274  TypeName *typename;
1275  HeapTuple tup;
1276  ObjectAddress address;
1277 
1278  /* Make a TypeName so we can use standard type lookup machinery */
1279  typename = makeTypeNameFromNameList(stmt->typeName);
1280  enum_type_oid = typenameTypeId(NULL, typename);
1281 
1282  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1283  if (!HeapTupleIsValid(tup))
1284  elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1285 
1286  /* Check it's an enum and check user has permission to ALTER the enum */
1287  checkEnumOwner(tup);
1288 
1289  ReleaseSysCache(tup);
1290 
1291  if (stmt->oldVal)
1292  {
1293  /* Rename an existing label */
1294  RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
1295  }
1296  else
1297  {
1298  /* Add a new label */
1299  AddEnumLabel(enum_type_oid, stmt->newVal,
1300  stmt->newValNeighbor, stmt->newValIsAfter,
1301  stmt->skipIfNewValExists);
1302  }
1303 
1304  InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1305 
1306  ObjectAddressSet(address, TypeRelationId, enum_type_oid);
1307 
1308  return address;
1309 }
#define stmt
Definition: indent_codes.h:59
void RenameEnumLabel(Oid enumTypeOid, const char *oldVal, const char *newVal)
Definition: pg_enum.c:607
void AddEnumLabel(Oid enumTypeOid, const char *newVal, const char *neighbor, bool newValIsAfter, bool skipIfExists)
Definition: pg_enum.c:292
static void checkEnumOwner(HeapTuple tup)
Definition: typecmds.c:1319

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

Referenced by ProcessUtilitySlow().

◆ AlterType()

ObjectAddress AlterType ( AlterTypeStmt stmt)

Definition at line 4312 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterTypeNamespace()

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

Definition at line 4055 of file typecmds.c.

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

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

Referenced by ExecAlterObjectSchemaStmt().

◆ AlterTypeNamespace_oid()

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

Definition at line 4104 of file typecmds.c.

4106 {
4107  Oid elemOid;
4108 
4109  /* check permissions on type */
4110  if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
4112 
4113  /* don't allow direct alteration of array types */
4114  elemOid = get_element_type(typeOid);
4115  if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
4116  {
4117  if (ignoreDependent)
4118  return InvalidOid;
4119  ereport(ERROR,
4120  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4121  errmsg("cannot alter array type %s",
4122  format_type_be(typeOid)),
4123  errhint("You can alter type %s, which will alter the array type as well.",
4124  format_type_be(elemOid))));
4125  }
4126 
4127  /* and do the work */
4128  return AlterTypeNamespaceInternal(typeOid, nspOid,
4129  false, /* isImplicitArray */
4130  ignoreDependent, /* ignoreDependent */
4131  true, /* errorOnTableType */
4132  objsMoved);
4133 }
#define OidIsValid(objectId)
Definition: c.h:775
int errhint(const char *fmt,...)
Definition: elog.c:1317
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2759
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2787
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool ignoreDependent, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4156

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

Referenced by AlterObjectNamespace_oid(), and AlterTypeNamespace().

◆ AlterTypeNamespaceInternal()

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

Definition at line 4156 of file typecmds.c.

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

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

Referenced by AlterTableNamespaceInternal(), and AlterTypeNamespace_oid().

◆ AlterTypeOwner()

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

Definition at line 3822 of file typecmds.c.

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

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

Referenced by ExecAlterOwnerStmt().

◆ AlterTypeOwner_oid()

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

Definition at line 3947 of file typecmds.c.

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

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

Referenced by AlterTypeOwner(), and shdepReassignOwned().

◆ AlterTypeOwnerInternal()

void AlterTypeOwnerInternal ( Oid  typeOid,
Oid  newOwnerId 
)

Definition at line 3987 of file typecmds.c.

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

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

Referenced by AlterTypeOwner_oid(), and ATExecChangeOwner().

◆ AssignTypeArrayOid()

Oid AssignTypeArrayOid ( void  )

Definition at line 2410 of file typecmds.c.

2411 {
2412  Oid type_array_oid;
2413 
2414  /* Use binary-upgrade override for pg_type.typarray? */
2415  if (IsBinaryUpgrade)
2416  {
2418  ereport(ERROR,
2419  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2420  errmsg("pg_type array OID value not set when in binary upgrade mode")));
2421 
2422  type_array_oid = binary_upgrade_next_array_pg_type_oid;
2424  }
2425  else
2426  {
2427  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2428 
2429  type_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2430  Anum_pg_type_oid);
2431  table_close(pg_type, AccessShareLock);
2432  }
2433 
2434  return type_array_oid;
2435 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:391
bool IsBinaryUpgrade
Definition: globals.c:118
Oid binary_upgrade_next_array_pg_type_oid
Definition: typecmds.c:109

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

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

◆ AssignTypeMultirangeArrayOid()

Oid AssignTypeMultirangeArrayOid ( void  )

Definition at line 2476 of file typecmds.c.

2477 {
2478  Oid type_multirange_array_oid;
2479 
2480  /* Use binary-upgrade override for pg_type.oid? */
2481  if (IsBinaryUpgrade)
2482  {
2484  ereport(ERROR,
2485  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2486  errmsg("pg_type multirange array OID value not set when in binary upgrade mode")));
2487 
2488  type_multirange_array_oid = binary_upgrade_next_mrng_array_pg_type_oid;
2490  }
2491  else
2492  {
2493  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2494 
2495  type_multirange_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2496  Anum_pg_type_oid);
2497  table_close(pg_type, AccessShareLock);
2498  }
2499 
2500  return type_multirange_array_oid;
2501 }
Oid binary_upgrade_next_mrng_array_pg_type_oid
Definition: typecmds.c:111

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

Referenced by DefineRange().

◆ AssignTypeMultirangeOid()

Oid AssignTypeMultirangeOid ( void  )

Definition at line 2443 of file typecmds.c.

2444 {
2445  Oid type_multirange_oid;
2446 
2447  /* Use binary-upgrade override for pg_type.oid? */
2448  if (IsBinaryUpgrade)
2449  {
2451  ereport(ERROR,
2452  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2453  errmsg("pg_type multirange OID value not set when in binary upgrade mode")));
2454 
2455  type_multirange_oid = binary_upgrade_next_mrng_pg_type_oid;
2457  }
2458  else
2459  {
2460  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2461 
2462  type_multirange_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2463  Anum_pg_type_oid);
2464  table_close(pg_type, AccessShareLock);
2465  }
2466 
2467  return type_multirange_oid;
2468 }
Oid binary_upgrade_next_mrng_pg_type_oid
Definition: typecmds.c:110

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

Referenced by DefineRange().

◆ checkDomainOwner()

void checkDomainOwner ( HeapTuple  tup)

Definition at line 3490 of file typecmds.c.

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

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

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

◆ DefineCompositeType()

ObjectAddress DefineCompositeType ( RangeVar typevar,
List coldeflist 
)

Definition at line 2518 of file typecmds.c.

2519 {
2520  CreateStmt *createStmt = makeNode(CreateStmt);
2521  Oid old_type_oid;
2522  Oid typeNamespace;
2523  ObjectAddress address;
2524 
2525  /*
2526  * now set the parameters for keys/inheritance etc. All of these are
2527  * uninteresting for composite types...
2528  */
2529  createStmt->relation = typevar;
2530  createStmt->tableElts = coldeflist;
2531  createStmt->inhRelations = NIL;
2532  createStmt->constraints = NIL;
2533  createStmt->options = NIL;
2534  createStmt->oncommit = ONCOMMIT_NOOP;
2535  createStmt->tablespacename = NULL;
2536  createStmt->if_not_exists = false;
2537 
2538  /*
2539  * Check for collision with an existing type name. If there is one and
2540  * it's an autogenerated array, we can rename it out of the way. This
2541  * check is here mainly to get a better error message about a "type"
2542  * instead of below about a "relation".
2543  */
2544  typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2545  NoLock, NULL);
2546  RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2547  old_type_oid =
2548  GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
2549  CStringGetDatum(createStmt->relation->relname),
2550  ObjectIdGetDatum(typeNamespace));
2551  if (OidIsValid(old_type_oid))
2552  {
2553  if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2554  ereport(ERROR,
2556  errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2557  }
2558 
2559  /*
2560  * Finally create the relation. This also creates the type.
2561  */
2562  DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2563  NULL);
2564 
2565  return address;
2566 }
#define NoLock
Definition: lockdefs.h:34
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:724
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition: namespace.c:831
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:905
@ ONCOMMIT_NOOP
Definition: primnodes.h:57
List * tableElts
Definition: parsenodes.h:2657
OnCommitAction oncommit
Definition: parsenodes.h:2665
List * options
Definition: parsenodes.h:2664
bool if_not_exists
Definition: parsenodes.h:2668
List * inhRelations
Definition: parsenodes.h:2658
RangeVar * relation
Definition: parsenodes.h:2656
char * tablespacename
Definition: parsenodes.h:2666
List * constraints
Definition: parsenodes.h:2663
char * relname
Definition: primnodes.h:82
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:106
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:685

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

Referenced by ProcessUtilitySlow().

◆ DefineDomain()

ObjectAddress DefineDomain ( CreateDomainStmt stmt)

Definition at line 697 of file typecmds.c.

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

References ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, AssignTypeArrayOid(), CommandCounterIncrement(), CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_NOTNULL, CONSTR_NULL, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, cookDefault(), CStringGetDatum(), deparse_expression(), domainAddCheckConstraint(), domainAddNotNullConstraint(), elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, format_type_be(), get_collation_oid(), get_namespace_name(), GETSTRUCT, GetSysCacheOid2, GetUserId(), InvalidOid, Constraint::is_no_inherit, IsA, lfirst, list_length(), make_parsestate(), makeArrayTypeName(), moveArrayTypeName(), NIL, nodeTag, nodeToString(), object_aclcheck(), OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, 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 1147 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ DefineRange()

ObjectAddress DefineRange ( ParseState pstate,
CreateRangeStmt stmt 
)

Definition at line 1346 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ DefineType()

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

Definition at line 152 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ RemoveTypeById()

void RemoveTypeById ( Oid  typeOid)

Definition at line 657 of file typecmds.c.

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

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

Referenced by doDeletion().

◆ RenameType()

ObjectAddress RenameType ( RenameStmt stmt)

Definition at line 3741 of file typecmds.c.

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

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

Referenced by ExecRenameStmt().