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

2907 {
2908  TypeName *typename;
2909  Oid domainoid;
2910  Relation typrel;
2911  HeapTuple tup;
2912  Form_pg_type typTup;
2913  Constraint *constr;
2914  char *ccbin;
2916 
2917  /* Make a TypeName so we can use standard type lookup machinery */
2918  typename = makeTypeNameFromNameList(names);
2919  domainoid = typenameTypeId(NULL, typename);
2920 
2921  /* Look up the domain in the type table */
2922  typrel = table_open(TypeRelationId, RowExclusiveLock);
2923 
2924  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2925  if (!HeapTupleIsValid(tup))
2926  elog(ERROR, "cache lookup failed for type %u", domainoid);
2927  typTup = (Form_pg_type) GETSTRUCT(tup);
2928 
2929  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2930  checkDomainOwner(tup);
2931 
2932  if (!IsA(newConstraint, Constraint))
2933  elog(ERROR, "unrecognized node type: %d",
2934  (int) nodeTag(newConstraint));
2935 
2936  constr = (Constraint *) newConstraint;
2937 
2938  switch (constr->contype)
2939  {
2940  case CONSTR_CHECK:
2941  case CONSTR_NOTNULL:
2942  /* processed below */
2943  break;
2944 
2945  case CONSTR_UNIQUE:
2946  ereport(ERROR,
2947  (errcode(ERRCODE_SYNTAX_ERROR),
2948  errmsg("unique constraints not possible for domains")));
2949  break;
2950 
2951  case CONSTR_PRIMARY:
2952  ereport(ERROR,
2953  (errcode(ERRCODE_SYNTAX_ERROR),
2954  errmsg("primary key constraints not possible for domains")));
2955  break;
2956 
2957  case CONSTR_EXCLUSION:
2958  ereport(ERROR,
2959  (errcode(ERRCODE_SYNTAX_ERROR),
2960  errmsg("exclusion constraints not possible for domains")));
2961  break;
2962 
2963  case CONSTR_FOREIGN:
2964  ereport(ERROR,
2965  (errcode(ERRCODE_SYNTAX_ERROR),
2966  errmsg("foreign key constraints not possible for domains")));
2967  break;
2968 
2971  case CONSTR_ATTR_DEFERRED:
2972  case CONSTR_ATTR_IMMEDIATE:
2973  ereport(ERROR,
2974  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2975  errmsg("specifying constraint deferrability not supported for domains")));
2976  break;
2977 
2978  default:
2979  elog(ERROR, "unrecognized constraint subtype: %d",
2980  (int) constr->contype);
2981  break;
2982  }
2983 
2984  if (constr->contype == CONSTR_CHECK)
2985  {
2986  /*
2987  * First, process the constraint expression and add an entry to
2988  * pg_constraint.
2989  */
2990 
2991  ccbin = domainAddCheckConstraint(domainoid, typTup->typnamespace,
2992  typTup->typbasetype, typTup->typtypmod,
2993  constr, NameStr(typTup->typname), constrAddr);
2994 
2995 
2996  /*
2997  * If requested to validate the constraint, test all values stored in
2998  * the attributes based on the domain the constraint is being added
2999  * to.
3000  */
3001  if (!constr->skip_validation)
3002  validateDomainCheckConstraint(domainoid, ccbin);
3003 
3004  /*
3005  * We must send out an sinval message for the domain, to ensure that
3006  * any dependent plans get rebuilt. Since this command doesn't change
3007  * the domain's pg_type row, that won't happen automatically; do it
3008  * manually.
3009  */
3010  CacheInvalidateHeapTuple(typrel, tup, NULL);
3011  }
3012  else if (constr->contype == CONSTR_NOTNULL)
3013  {
3014  /* Is the domain already set NOT NULL? */
3015  if (typTup->typnotnull)
3016  {
3017  table_close(typrel, RowExclusiveLock);
3018  return address;
3019  }
3020  domainAddNotNullConstraint(domainoid, typTup->typnamespace,
3021  typTup->typbasetype, typTup->typtypmod,
3022  constr, NameStr(typTup->typname), constrAddr);
3023 
3024  if (!constr->skip_validation)
3026 
3027  typTup->typnotnull = true;
3028  CatalogTupleUpdate(typrel, &tup->t_self, tup);
3029  }
3030 
3031  ObjectAddressSet(address, TypeRelationId, domainoid);
3032 
3033  /* Clean up */
3034  table_close(typrel, RowExclusiveLock);
3035 
3036  return address;
3037 }
#define NameStr(name)
Definition: c.h:700
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#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:1493
#define RowExclusiveLock
Definition: lockdefs.h:38
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:481
#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:2734
@ CONSTR_ATTR_DEFERRED
Definition: parsenodes.h:2737
@ CONSTR_UNIQUE
Definition: parsenodes.h:2732
@ CONSTR_ATTR_NOT_DEFERRABLE
Definition: parsenodes.h:2736
@ CONSTR_NOTNULL
Definition: parsenodes.h:2726
@ CONSTR_ATTR_IMMEDIATE
Definition: parsenodes.h:2738
@ CONSTR_CHECK
Definition: parsenodes.h:2730
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2733
@ CONSTR_ATTR_DEFERRABLE
Definition: parsenodes.h:2735
@ CONSTR_PRIMARY
Definition: parsenodes.h:2731
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:2756
bool skip_validation
Definition: parsenodes.h:2760
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static void validateDomainCheckConstraint(Oid domainoid, const char *ccbin)
Definition: typecmds.c:3209
static char * domainAddCheckConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:3518
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3498
static void domainAddNotNullConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:3677
static void validateDomainNotNullConstraint(Oid domainoid)
Definition: typecmds.c:3144

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

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

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

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

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

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

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

1280 {
1281  Oid enum_type_oid;
1282  TypeName *typename;
1283  HeapTuple tup;
1284  ObjectAddress address;
1285 
1286  /* Make a TypeName so we can use standard type lookup machinery */
1287  typename = makeTypeNameFromNameList(stmt->typeName);
1288  enum_type_oid = typenameTypeId(NULL, typename);
1289 
1290  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1291  if (!HeapTupleIsValid(tup))
1292  elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1293 
1294  /* Check it's an enum and check user has permission to ALTER the enum */
1295  checkEnumOwner(tup);
1296 
1297  ReleaseSysCache(tup);
1298 
1299  if (stmt->oldVal)
1300  {
1301  /* Rename an existing label */
1302  RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
1303  }
1304  else
1305  {
1306  /* Add a new label */
1307  AddEnumLabel(enum_type_oid, stmt->newVal,
1308  stmt->newValNeighbor, stmt->newValIsAfter,
1309  stmt->skipIfNewValExists);
1310  }
1311 
1312  InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1313 
1314  ObjectAddressSet(address, TypeRelationId, enum_type_oid);
1315 
1316  return address;
1317 }
#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:1327

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

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

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

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

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

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

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

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

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

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

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

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

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

Referenced by AlterTypeOwner(), and shdepReassignOwned_Owner().

◆ AlterTypeOwnerInternal()

void AlterTypeOwnerInternal ( Oid  typeOid,
Oid  newOwnerId 
)

Definition at line 3997 of file typecmds.c.

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

2419 {
2420  Oid type_array_oid;
2421 
2422  /* Use binary-upgrade override for pg_type.typarray? */
2423  if (IsBinaryUpgrade)
2424  {
2426  ereport(ERROR,
2427  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2428  errmsg("pg_type array OID value not set when in binary upgrade mode")));
2429 
2430  type_array_oid = binary_upgrade_next_array_pg_type_oid;
2432  }
2433  else
2434  {
2435  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2436 
2437  type_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2438  Anum_pg_type_oid);
2439  table_close(pg_type, AccessShareLock);
2440  }
2441 
2442  return type_array_oid;
2443 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
bool IsBinaryUpgrade
Definition: globals.c:120
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 2484 of file typecmds.c.

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

2452 {
2453  Oid type_multirange_oid;
2454 
2455  /* Use binary-upgrade override for pg_type.oid? */
2456  if (IsBinaryUpgrade)
2457  {
2459  ereport(ERROR,
2460  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2461  errmsg("pg_type multirange OID value not set when in binary upgrade mode")));
2462 
2463  type_multirange_oid = binary_upgrade_next_mrng_pg_type_oid;
2465  }
2466  else
2467  {
2468  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2469 
2470  type_multirange_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2471  Anum_pg_type_oid);
2472  table_close(pg_type, AccessShareLock);
2473  }
2474 
2475  return type_multirange_oid;
2476 }
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 3498 of file typecmds.c.

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

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

2527 {
2528  CreateStmt *createStmt = makeNode(CreateStmt);
2529  Oid old_type_oid;
2530  Oid typeNamespace;
2531  ObjectAddress address;
2532 
2533  /*
2534  * now set the parameters for keys/inheritance etc. All of these are
2535  * uninteresting for composite types...
2536  */
2537  createStmt->relation = typevar;
2538  createStmt->tableElts = coldeflist;
2539  createStmt->inhRelations = NIL;
2540  createStmt->constraints = NIL;
2541  createStmt->options = NIL;
2542  createStmt->oncommit = ONCOMMIT_NOOP;
2543  createStmt->tablespacename = NULL;
2544  createStmt->if_not_exists = false;
2545 
2546  /*
2547  * Check for collision with an existing type name. If there is one and
2548  * it's an autogenerated array, we can rename it out of the way. This
2549  * check is here mainly to get a better error message about a "type"
2550  * instead of below about a "relation".
2551  */
2552  typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2553  NoLock, NULL);
2554  RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2555  old_type_oid =
2556  GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
2557  CStringGetDatum(createStmt->relation->relname),
2558  ObjectIdGetDatum(typeNamespace));
2559  if (OidIsValid(old_type_oid))
2560  {
2561  if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2562  ereport(ERROR,
2564  errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2565  }
2566 
2567  /*
2568  * Finally create the relation. This also creates the type.
2569  */
2570  DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2571  NULL);
2572 
2573  return address;
2574 }
#define NoLock
Definition: lockdefs.h:34
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:739
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition: namespace.c:846
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:2676
OnCommitAction oncommit
Definition: parsenodes.h:2685
List * options
Definition: parsenodes.h:2684
bool if_not_exists
Definition: parsenodes.h:2688
List * inhRelations
Definition: parsenodes.h:2677
RangeVar * relation
Definition: parsenodes.h:2675
char * tablespacename
Definition: parsenodes.h:2686
List * constraints
Definition: parsenodes.h:2682
char * relname
Definition: primnodes.h:82
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:111
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:713

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  if (constr->is_no_inherit)
948  ereport(ERROR,
949  errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
950  errmsg("not-null constraints for domains cannot be marked NO INHERIT"));
951  typNotNull = true;
952  nullDefined = true;
953  break;
954 
955  case CONSTR_NULL:
956  if (nullDefined && typNotNull)
957  ereport(ERROR,
958  (errcode(ERRCODE_SYNTAX_ERROR),
959  errmsg("conflicting NULL/NOT NULL constraints")));
960  typNotNull = false;
961  nullDefined = true;
962  break;
963 
964  case CONSTR_CHECK:
965 
966  /*
967  * Check constraints are handled after domain creation, as
968  * they require the Oid of the domain; at this point we can
969  * only check that they're not marked NO INHERIT, because that
970  * would be bogus.
971  */
972  if (constr->is_no_inherit)
973  ereport(ERROR,
974  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
975  errmsg("check constraints for domains cannot be marked NO INHERIT")));
976  break;
977 
978  /*
979  * All else are error cases
980  */
981  case CONSTR_UNIQUE:
982  ereport(ERROR,
983  (errcode(ERRCODE_SYNTAX_ERROR),
984  errmsg("unique constraints not possible for domains")));
985  break;
986 
987  case CONSTR_PRIMARY:
988  ereport(ERROR,
989  (errcode(ERRCODE_SYNTAX_ERROR),
990  errmsg("primary key constraints not possible for domains")));
991  break;
992 
993  case CONSTR_EXCLUSION:
994  ereport(ERROR,
995  (errcode(ERRCODE_SYNTAX_ERROR),
996  errmsg("exclusion constraints not possible for domains")));
997  break;
998 
999  case CONSTR_FOREIGN:
1000  ereport(ERROR,
1001  (errcode(ERRCODE_SYNTAX_ERROR),
1002  errmsg("foreign key constraints not possible for domains")));
1003  break;
1004 
1007  case CONSTR_ATTR_DEFERRED:
1008  case CONSTR_ATTR_IMMEDIATE:
1009  ereport(ERROR,
1010  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1011  errmsg("specifying constraint deferrability not supported for domains")));
1012  break;
1013 
1014  case CONSTR_GENERATED:
1015  case CONSTR_IDENTITY:
1016  ereport(ERROR,
1017  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1018  errmsg("specifying GENERATED not supported for domains")));
1019  break;
1020 
1021  /* no default, to let compiler warn about missing case */
1022  }
1023  }
1024 
1025  /* Allocate OID for array type */
1026  domainArrayOid = AssignTypeArrayOid();
1027 
1028  /*
1029  * Have TypeCreate do all the real work.
1030  */
1031  address =
1032  TypeCreate(InvalidOid, /* no predetermined type OID */
1033  domainName, /* type name */
1034  domainNamespace, /* namespace */
1035  InvalidOid, /* relation oid (n/a here) */
1036  0, /* relation kind (ditto) */
1037  GetUserId(), /* owner's ID */
1038  internalLength, /* internal size */
1039  TYPTYPE_DOMAIN, /* type-type (domain type) */
1040  category, /* type-category */
1041  false, /* domain types are never preferred */
1042  delimiter, /* array element delimiter */
1043  inputProcedure, /* input procedure */
1044  outputProcedure, /* output procedure */
1045  receiveProcedure, /* receive procedure */
1046  sendProcedure, /* send procedure */
1047  InvalidOid, /* typmodin procedure - none */
1048  InvalidOid, /* typmodout procedure - none */
1049  analyzeProcedure, /* analyze procedure */
1050  InvalidOid, /* subscript procedure - none */
1051  InvalidOid, /* no array element type */
1052  false, /* this isn't an array */
1053  domainArrayOid, /* array type we are about to create */
1054  basetypeoid, /* base type ID */
1055  defaultValue, /* default type value (text) */
1056  defaultValueBin, /* default type value (binary) */
1057  byValue, /* passed by value */
1058  alignment, /* required alignment */
1059  storage, /* TOAST strategy */
1060  basetypeMod, /* typeMod value */
1061  typNDims, /* Array dimensions for base type */
1062  typNotNull, /* Type NOT NULL */
1063  domaincoll); /* type's collation */
1064 
1065  /*
1066  * Create the array type that goes with it.
1067  */
1068  domainArrayName = makeArrayTypeName(domainName, domainNamespace);
1069 
1070  /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for arrays */
1071  alignment = (alignment == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
1072 
1073  TypeCreate(domainArrayOid, /* force assignment of this type OID */
1074  domainArrayName, /* type name */
1075  domainNamespace, /* namespace */
1076  InvalidOid, /* relation oid (n/a here) */
1077  0, /* relation kind (ditto) */
1078  GetUserId(), /* owner's ID */
1079  -1, /* internal size (always varlena) */
1080  TYPTYPE_BASE, /* type-type (base type) */
1081  TYPCATEGORY_ARRAY, /* type-category (array) */
1082  false, /* array types are never preferred */
1083  delimiter, /* array element delimiter */
1084  F_ARRAY_IN, /* input procedure */
1085  F_ARRAY_OUT, /* output procedure */
1086  F_ARRAY_RECV, /* receive procedure */
1087  F_ARRAY_SEND, /* send procedure */
1088  InvalidOid, /* typmodin procedure - none */
1089  InvalidOid, /* typmodout procedure - none */
1090  F_ARRAY_TYPANALYZE, /* analyze procedure */
1091  F_ARRAY_SUBSCRIPT_HANDLER, /* array subscript procedure */
1092  address.objectId, /* element type ID */
1093  true, /* yes this is an array type */
1094  InvalidOid, /* no further array type */
1095  InvalidOid, /* base type ID */
1096  NULL, /* never a default type value */
1097  NULL, /* binary default isn't sent either */
1098  false, /* never passed by value */
1099  alignment, /* see above */
1100  TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
1101  -1, /* typMod (Domains only) */
1102  0, /* Array dimensions of typbasetype */
1103  false, /* Type NOT NULL */
1104  domaincoll); /* type's collation */
1105 
1106  pfree(domainArrayName);
1107 
1108  /*
1109  * Process constraints which refer to the domain ID returned by TypeCreate
1110  */
1111  foreach(listptr, schema)
1112  {
1113  Constraint *constr = lfirst(listptr);
1114 
1115  /* it must be a Constraint, per check above */
1116 
1117  switch (constr->contype)
1118  {
1119  case CONSTR_CHECK:
1120  domainAddCheckConstraint(address.objectId, domainNamespace,
1121  basetypeoid, basetypeMod,
1122  constr, domainName, NULL);
1123  break;
1124 
1125  case CONSTR_NOTNULL:
1126  domainAddNotNullConstraint(address.objectId, domainNamespace,
1127  basetypeoid, basetypeMod,
1128  constr, domainName, NULL);
1129  break;
1130 
1131  /* Other constraint types were fully processed above */
1132 
1133  default:
1134  break;
1135  }
1136 
1137  /* CCI so we can detect duplicate constraint names */
1139  }
1140 
1141  /*
1142  * Now we can clean up.
1143  */
1144  ReleaseSysCache(typeTup);
1145 
1146  return address;
1147 }
int16_t int16
Definition: c.h:480
int32_t int32
Definition: c.h:481
#define storage
Definition: indent_codes.h:68
void pfree(void *pointer)
Definition: mcxt.c:1521
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition: namespace.c:3487
Oid get_collation_oid(List *collname, bool missing_ok)
Definition: namespace.c:3971
#define ACL_USAGE
Definition: parsenodes.h:84
@ CONSTR_IDENTITY
Definition: parsenodes.h:2728
@ CONSTR_DEFAULT
Definition: parsenodes.h:2727
@ CONSTR_NULL
Definition: parsenodes.h:2724
@ CONSTR_GENERATED
Definition: parsenodes.h:2729
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:2762
Node * raw_expr
Definition: parsenodes.h:2763
Definition: pg_list.h:54
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2418
void CommandCounterIncrement(void)
Definition: xact.c:1099

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_GENERATED, CONSTR_IDENTITY, CONSTR_NOTNULL, CONSTR_NULL, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, cookDefault(), CStringGetDatum(), deparse_expression(), domainAddCheckConstraint(), domainAddNotNullConstraint(), elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, format_type_be(), get_collation_oid(), get_namespace_name(), GETSTRUCT, GetSysCacheOid2, GetUserId(), InvalidOid, Constraint::is_no_inherit, IsA, lfirst, list_length(), 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 1155 of file typecmds.c.

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

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

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:3594
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
@ OBJECT_FUNCTION
Definition: parsenodes.h:2287
ObjectAddress TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
Definition: pg_type.c:57
ParseLoc location
Definition: parsenodes.h:821
static Oid findTypeOutputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2024
static Oid findTypeInputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1961

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

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

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