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 *constr, 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, ObjectAddresses *objsMoved)
 
Oid AlterTypeNamespaceInternal (Oid typeOid, Oid nspOid, bool isImplicitArray, 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 constr,
ObjectAddress constrAddr 
)

Definition at line 2915 of file typecmds.c.

2917 {
2918  TypeName *typename;
2919  Oid domainoid;
2920  Relation typrel;
2921  HeapTuple tup;
2922  Form_pg_type typTup;
2923  Constraint *constr;
2924  char *ccbin;
2925  ObjectAddress address;
2926 
2927  /* Make a TypeName so we can use standard type lookup machinery */
2928  typename = makeTypeNameFromNameList(names);
2929  domainoid = typenameTypeId(NULL, typename);
2930 
2931  /* Look up the domain in the type table */
2932  typrel = table_open(TypeRelationId, RowExclusiveLock);
2933 
2934  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2935  if (!HeapTupleIsValid(tup))
2936  elog(ERROR, "cache lookup failed for type %u", domainoid);
2937  typTup = (Form_pg_type) GETSTRUCT(tup);
2938 
2939  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2940  checkDomainOwner(tup);
2941 
2942  if (!IsA(newConstraint, Constraint))
2943  elog(ERROR, "unrecognized node type: %d",
2944  (int) nodeTag(newConstraint));
2945 
2946  constr = (Constraint *) newConstraint;
2947 
2948  switch (constr->contype)
2949  {
2950  case CONSTR_CHECK:
2951  /* processed below */
2952  break;
2953 
2954  case CONSTR_UNIQUE:
2955  ereport(ERROR,
2956  (errcode(ERRCODE_SYNTAX_ERROR),
2957  errmsg("unique constraints not possible for domains")));
2958  break;
2959 
2960  case CONSTR_PRIMARY:
2961  ereport(ERROR,
2962  (errcode(ERRCODE_SYNTAX_ERROR),
2963  errmsg("primary key constraints not possible for domains")));
2964  break;
2965 
2966  case CONSTR_EXCLUSION:
2967  ereport(ERROR,
2968  (errcode(ERRCODE_SYNTAX_ERROR),
2969  errmsg("exclusion constraints not possible for domains")));
2970  break;
2971 
2972  case CONSTR_FOREIGN:
2973  ereport(ERROR,
2974  (errcode(ERRCODE_SYNTAX_ERROR),
2975  errmsg("foreign key constraints not possible for domains")));
2976  break;
2977 
2980  case CONSTR_ATTR_DEFERRED:
2981  case CONSTR_ATTR_IMMEDIATE:
2982  ereport(ERROR,
2983  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2984  errmsg("specifying constraint deferrability not supported for domains")));
2985  break;
2986 
2987  default:
2988  elog(ERROR, "unrecognized constraint subtype: %d",
2989  (int) constr->contype);
2990  break;
2991  }
2992 
2993  /*
2994  * Since all other constraint types throw errors, this must be a check
2995  * constraint. First, process the constraint expression and add an entry
2996  * to pg_constraint.
2997  */
2998 
2999  ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
3000  typTup->typbasetype, typTup->typtypmod,
3001  constr, NameStr(typTup->typname), constrAddr);
3002 
3003  /*
3004  * If requested to validate the constraint, test all values stored in the
3005  * attributes based on the domain the constraint is being added to.
3006  */
3007  if (!constr->skip_validation)
3008  validateDomainConstraint(domainoid, ccbin);
3009 
3010  /*
3011  * We must send out an sinval message for the domain, to ensure that any
3012  * dependent plans get rebuilt. Since this command doesn't change the
3013  * domain's pg_type row, that won't happen automatically; do it manually.
3014  */
3015  CacheInvalidateHeapTuple(typrel, tup, NULL);
3016 
3017  ObjectAddressSet(address, TypeRelationId, domainoid);
3018 
3019  /* Clean up */
3020  table_close(typrel, RowExclusiveLock);
3021 
3022  return address;
3023 }
#define NameStr(name)
Definition: c.h:692
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1207
#define RowExclusiveLock
Definition: lockdefs.h:38
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:457
#define IsA(nodeptr, _type_)
Definition: nodes.h:625
#define nodeTag(nodeptr)
Definition: nodes.h:579
#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:2589
@ CONSTR_ATTR_DEFERRED
Definition: parsenodes.h:2592
@ CONSTR_UNIQUE
Definition: parsenodes.h:2587
@ CONSTR_ATTR_NOT_DEFERRABLE
Definition: parsenodes.h:2591
@ CONSTR_ATTR_IMMEDIATE
Definition: parsenodes.h:2593
@ CONSTR_CHECK
Definition: parsenodes.h:2585
@ CONSTR_EXCLUSION
Definition: parsenodes.h:2588
@ CONSTR_ATTR_DEFERRABLE
Definition: parsenodes.h:2590
@ CONSTR_PRIMARY
Definition: parsenodes.h:2586
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
unsigned int Oid
Definition: postgres_ext.h:31
ConstrType contype
Definition: parsenodes.h:2611
bool skip_validation
Definition: parsenodes.h:2658
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ TYPEOID
Definition: syscache.h:114
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
static void validateDomainConstraint(Oid domainoid, char *ccbin)
Definition: typecmds.c:3133
static char * domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:3442
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3422

References CacheInvalidateHeapTuple(), checkDomainOwner(), CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_CHECK, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, domainAddConstraint(), elog(), ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, IsA, makeTypeNameFromNameList(), NameStr, nodeTag, ObjectAddressSet, ObjectIdGetDatum, RowExclusiveLock, SearchSysCacheCopy1, Constraint::skip_validation, table_close(), table_open(), typenameTypeId(), TYPEOID, and validateDomainConstraint().

Referenced by ATExecCmd(), and ProcessUtilitySlow().

◆ AlterDomainDefault()

ObjectAddress AlterDomainDefault ( List names,
Node defaultRaw 
)

Definition at line 2564 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterDomainDropConstraint()

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

Definition at line 2816 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

◆ AlterDomainNotNull()

ObjectAddress AlterDomainNotNull ( List names,
bool  notNull 
)

Definition at line 2696 of file typecmds.c.

2697 {
2698  TypeName *typename;
2699  Oid domainoid;
2700  Relation typrel;
2701  HeapTuple tup;
2702  Form_pg_type typTup;
2704 
2705  /* Make a TypeName so we can use standard type lookup machinery */
2706  typename = makeTypeNameFromNameList(names);
2707  domainoid = typenameTypeId(NULL, typename);
2708 
2709  /* Look up the domain in the type table */
2710  typrel = table_open(TypeRelationId, RowExclusiveLock);
2711 
2712  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2713  if (!HeapTupleIsValid(tup))
2714  elog(ERROR, "cache lookup failed for type %u", domainoid);
2715  typTup = (Form_pg_type) GETSTRUCT(tup);
2716 
2717  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2718  checkDomainOwner(tup);
2719 
2720  /* Is the domain already set to the desired constraint? */
2721  if (typTup->typnotnull == notNull)
2722  {
2723  table_close(typrel, RowExclusiveLock);
2724  return address;
2725  }
2726 
2727  /* Adding a NOT NULL constraint requires checking existing columns */
2728  if (notNull)
2729  {
2730  List *rels;
2731  ListCell *rt;
2732 
2733  /* Fetch relation list with attributes based on this domain */
2734  /* ShareLock is sufficient to prevent concurrent data changes */
2735 
2736  rels = get_rels_with_domain(domainoid, ShareLock);
2737 
2738  foreach(rt, rels)
2739  {
2740  RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2741  Relation testrel = rtc->rel;
2742  TupleDesc tupdesc = RelationGetDescr(testrel);
2743  TupleTableSlot *slot;
2744  TableScanDesc scan;
2745  Snapshot snapshot;
2746 
2747  /* Scan all tuples in this relation */
2748  snapshot = RegisterSnapshot(GetLatestSnapshot());
2749  scan = table_beginscan(testrel, snapshot, 0, NULL);
2750  slot = table_slot_create(testrel, NULL);
2751  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
2752  {
2753  int i;
2754 
2755  /* Test attributes that are of the domain */
2756  for (i = 0; i < rtc->natts; i++)
2757  {
2758  int attnum = rtc->atts[i];
2759  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2760 
2761  if (slot_attisnull(slot, attnum))
2762  {
2763  /*
2764  * In principle the auxiliary information for this
2765  * error should be errdatatype(), but errtablecol()
2766  * seems considerably more useful in practice. Since
2767  * this code only executes in an ALTER DOMAIN command,
2768  * the client should already know which domain is in
2769  * question.
2770  */
2771  ereport(ERROR,
2772  (errcode(ERRCODE_NOT_NULL_VIOLATION),
2773  errmsg("column \"%s\" of table \"%s\" contains null values",
2774  NameStr(attr->attname),
2775  RelationGetRelationName(testrel)),
2776  errtablecol(testrel, attnum)));
2777  }
2778  }
2779  }
2781  table_endscan(scan);
2782  UnregisterSnapshot(snapshot);
2783 
2784  /* Close each rel after processing, but keep lock */
2785  table_close(testrel, NoLock);
2786  }
2787  }
2788 
2789  /*
2790  * Okay to update pg_type row. We can scribble on typTup because it's a
2791  * copy.
2792  */
2793  typTup->typnotnull = notNull;
2794 
2795  CatalogTupleUpdate(typrel, &tup->t_self, tup);
2796 
2797  InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2798 
2799  ObjectAddressSet(address, TypeRelationId, domainoid);
2800 
2801  /* Clean up */
2802  heap_freetuple(tup);
2803  table_close(typrel, RowExclusiveLock);
2804 
2805  return address;
2806 }
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1254
int i
Definition: isn.c:73
#define NoLock
Definition: lockdefs.h:34
#define ShareLock
Definition: lockdefs.h:40
const ObjectAddress InvalidObjectAddress
int16 attnum
Definition: pg_attribute.h:83
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:207
#define lfirst(lc)
Definition: pg_list.h:170
#define RelationGetRelationName(relation)
Definition: rel.h:522
int errtablecol(Relation rel, int attnum)
Definition: relcache.c:5830
@ ForwardScanDirection
Definition: sdir.h:26
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:325
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:869
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:827
Definition: pg_list.h:52
int * atts
Definition: typecmds.c:83
Relation rel
Definition: typecmds.c:81
int natts
Definition: typecmds.c:82
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:91
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:885
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:993
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1034
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static bool slot_attisnull(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:367
static List * get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
Definition: typecmds.c:3253

References attnum, RelToCheck::atts, CatalogTupleUpdate(), checkDomainOwner(), elog(), ereport, errcode(), errmsg(), ERROR, errtablecol(), ExecDropSingleTupleTableSlot(), ForwardScanDirection, get_rels_with_domain(), GetLatestSnapshot(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, i, InvalidObjectAddress, InvokeObjectPostAlterHook, lfirst, makeTypeNameFromNameList(), NameStr, RelToCheck::natts, NoLock, ObjectAddressSet, ObjectIdGetDatum, RegisterSnapshot(), RelToCheck::rel, RelationGetDescr, RelationGetRelationName, RowExclusiveLock, SearchSysCacheCopy1, ShareLock, slot_attisnull(), HeapTupleData::t_self, table_beginscan(), table_close(), table_endscan(), table_open(), table_scan_getnextslot(), table_slot_create(), TupleDescAttr, typenameTypeId(), TYPEOID, and UnregisterSnapshot().

Referenced by ProcessUtilitySlow().

◆ AlterDomainValidateConstraint()

ObjectAddress AlterDomainValidateConstraint ( List names,
const char *  constrName 
)

Definition at line 3031 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterEnum()

ObjectAddress AlterEnum ( AlterEnumStmt stmt)

Definition at line 1261 of file typecmds.c.

1262 {
1263  Oid enum_type_oid;
1264  TypeName *typename;
1265  HeapTuple tup;
1266  ObjectAddress address;
1267 
1268  /* Make a TypeName so we can use standard type lookup machinery */
1269  typename = makeTypeNameFromNameList(stmt->typeName);
1270  enum_type_oid = typenameTypeId(NULL, typename);
1271 
1272  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1273  if (!HeapTupleIsValid(tup))
1274  elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1275 
1276  /* Check it's an enum and check user has permission to ALTER the enum */
1277  checkEnumOwner(tup);
1278 
1279  ReleaseSysCache(tup);
1280 
1281  if (stmt->oldVal)
1282  {
1283  /* Rename an existing label */
1284  RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
1285  }
1286  else
1287  {
1288  /* Add a new label */
1289  AddEnumLabel(enum_type_oid, stmt->newVal,
1290  stmt->newValNeighbor, stmt->newValIsAfter,
1291  stmt->skipIfNewValExists);
1292  }
1293 
1294  InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1295 
1296  ObjectAddressSet(address, TypeRelationId, enum_type_oid);
1297 
1298  return address;
1299 }
void RenameEnumLabel(Oid enumTypeOid, const char *oldVal, const char *newVal)
Definition: pg_enum.c:508
void AddEnumLabel(Oid enumTypeOid, const char *newVal, const char *neighbor, bool newValIsAfter, bool skipIfExists)
Definition: pg_enum.c:208
char * newValNeighbor
Definition: parsenodes.h:3598
List * typeName
Definition: parsenodes.h:3595
bool skipIfNewValExists
Definition: parsenodes.h:3600
bool newValIsAfter
Definition: parsenodes.h:3599
static void checkEnumOwner(HeapTuple tup)
Definition: typecmds.c:1309

References AddEnumLabel(), checkEnumOwner(), elog(), ERROR, HeapTupleIsValid, InvokeObjectPostAlterHook, makeTypeNameFromNameList(), AlterEnumStmt::newVal, AlterEnumStmt::newValIsAfter, AlterEnumStmt::newValNeighbor, ObjectAddressSet, ObjectIdGetDatum, AlterEnumStmt::oldVal, ReleaseSysCache(), RenameEnumLabel(), SearchSysCache1(), AlterEnumStmt::skipIfNewValExists, AlterEnumStmt::typeName, typenameTypeId(), and TYPEOID.

Referenced by ProcessUtilitySlow().

◆ AlterType()

ObjectAddress AlterType ( AlterTypeStmt stmt)

Definition at line 4097 of file typecmds.c.

4098 {
4099  ObjectAddress address;
4100  Relation catalog;
4101  TypeName *typename;
4102  HeapTuple tup;
4103  Oid typeOid;
4104  Form_pg_type typForm;
4105  bool requireSuper = false;
4106  AlterTypeRecurseParams atparams;
4107  ListCell *pl;
4108 
4109  catalog = table_open(TypeRelationId, RowExclusiveLock);
4110 
4111  /* Make a TypeName so we can use standard type lookup machinery */
4112  typename = makeTypeNameFromNameList(stmt->typeName);
4113  tup = typenameType(NULL, typename, NULL);
4114 
4115  typeOid = typeTypeId(tup);
4116  typForm = (Form_pg_type) GETSTRUCT(tup);
4117 
4118  /* Process options */
4119  memset(&atparams, 0, sizeof(atparams));
4120  foreach(pl, stmt->options)
4121  {
4122  DefElem *defel = (DefElem *) lfirst(pl);
4123 
4124  if (strcmp(defel->defname, "storage") == 0)
4125  {
4126  char *a = defGetString(defel);
4127 
4128  if (pg_strcasecmp(a, "plain") == 0)
4129  atparams.storage = TYPSTORAGE_PLAIN;
4130  else if (pg_strcasecmp(a, "external") == 0)
4131  atparams.storage = TYPSTORAGE_EXTERNAL;
4132  else if (pg_strcasecmp(a, "extended") == 0)
4133  atparams.storage = TYPSTORAGE_EXTENDED;
4134  else if (pg_strcasecmp(a, "main") == 0)
4135  atparams.storage = TYPSTORAGE_MAIN;
4136  else
4137  ereport(ERROR,
4138  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4139  errmsg("storage \"%s\" not recognized", a)));
4140 
4141  /*
4142  * Validate the storage request. If the type isn't varlena, it
4143  * certainly doesn't support non-PLAIN storage.
4144  */
4145  if (atparams.storage != TYPSTORAGE_PLAIN && typForm->typlen != -1)
4146  ereport(ERROR,
4147  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
4148  errmsg("fixed-size types must have storage PLAIN")));
4149 
4150  /*
4151  * Switching from PLAIN to non-PLAIN is allowed, but it requires
4152  * superuser, since we can't validate that the type's C functions
4153  * will support it. Switching from non-PLAIN to PLAIN is
4154  * disallowed outright, because it's not practical to ensure that
4155  * no tables have toasted values of the type. Switching among
4156  * different non-PLAIN settings is OK, since it just constitutes a
4157  * change in the strategy requested for columns created in the
4158  * future.
4159  */
4160  if (atparams.storage != TYPSTORAGE_PLAIN &&
4161  typForm->typstorage == TYPSTORAGE_PLAIN)
4162  requireSuper = true;
4163  else if (atparams.storage == TYPSTORAGE_PLAIN &&
4164  typForm->typstorage != TYPSTORAGE_PLAIN)
4165  ereport(ERROR,
4166  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
4167  errmsg("cannot change type's storage to PLAIN")));
4168 
4169  atparams.updateStorage = true;
4170  }
4171  else if (strcmp(defel->defname, "receive") == 0)
4172  {
4173  if (defel->arg != NULL)
4174  atparams.receiveOid =
4176  typeOid);
4177  else
4178  atparams.receiveOid = InvalidOid; /* NONE, remove function */
4179  atparams.updateReceive = true;
4180  /* Replacing an I/O function requires superuser. */
4181  requireSuper = true;
4182  }
4183  else if (strcmp(defel->defname, "send") == 0)
4184  {
4185  if (defel->arg != NULL)
4186  atparams.sendOid =
4188  typeOid);
4189  else
4190  atparams.sendOid = InvalidOid; /* NONE, remove function */
4191  atparams.updateSend = true;
4192  /* Replacing an I/O function requires superuser. */
4193  requireSuper = true;
4194  }
4195  else if (strcmp(defel->defname, "typmod_in") == 0)
4196  {
4197  if (defel->arg != NULL)
4198  atparams.typmodinOid =
4200  else
4201  atparams.typmodinOid = InvalidOid; /* NONE, remove function */
4202  atparams.updateTypmodin = true;
4203  /* Replacing an I/O function requires superuser. */
4204  requireSuper = true;
4205  }
4206  else if (strcmp(defel->defname, "typmod_out") == 0)
4207  {
4208  if (defel->arg != NULL)
4209  atparams.typmodoutOid =
4211  else
4212  atparams.typmodoutOid = InvalidOid; /* NONE, remove function */
4213  atparams.updateTypmodout = true;
4214  /* Replacing an I/O function requires superuser. */
4215  requireSuper = true;
4216  }
4217  else if (strcmp(defel->defname, "analyze") == 0)
4218  {
4219  if (defel->arg != NULL)
4220  atparams.analyzeOid =
4222  typeOid);
4223  else
4224  atparams.analyzeOid = InvalidOid; /* NONE, remove function */
4225  atparams.updateAnalyze = true;
4226  /* Replacing an analyze function requires superuser. */
4227  requireSuper = true;
4228  }
4229  else if (strcmp(defel->defname, "subscript") == 0)
4230  {
4231  if (defel->arg != NULL)
4232  atparams.subscriptOid =
4234  typeOid);
4235  else
4236  atparams.subscriptOid = InvalidOid; /* NONE, remove function */
4237  atparams.updateSubscript = true;
4238  /* Replacing a subscript function requires superuser. */
4239  requireSuper = true;
4240  }
4241 
4242  /*
4243  * The rest of the options that CREATE accepts cannot be changed.
4244  * Check for them so that we can give a meaningful error message.
4245  */
4246  else if (strcmp(defel->defname, "input") == 0 ||
4247  strcmp(defel->defname, "output") == 0 ||
4248  strcmp(defel->defname, "internallength") == 0 ||
4249  strcmp(defel->defname, "passedbyvalue") == 0 ||
4250  strcmp(defel->defname, "alignment") == 0 ||
4251  strcmp(defel->defname, "like") == 0 ||
4252  strcmp(defel->defname, "category") == 0 ||
4253  strcmp(defel->defname, "preferred") == 0 ||
4254  strcmp(defel->defname, "default") == 0 ||
4255  strcmp(defel->defname, "element") == 0 ||
4256  strcmp(defel->defname, "delimiter") == 0 ||
4257  strcmp(defel->defname, "collatable") == 0)
4258  ereport(ERROR,
4259  (errcode(ERRCODE_SYNTAX_ERROR),
4260  errmsg("type attribute \"%s\" cannot be changed",
4261  defel->defname)));
4262  else
4263  ereport(ERROR,
4264  (errcode(ERRCODE_SYNTAX_ERROR),
4265  errmsg("type attribute \"%s\" not recognized",
4266  defel->defname)));
4267  }
4268 
4269  /*
4270  * Permissions check. Require superuser if we decided the command
4271  * requires that, else must own the type.
4272  */
4273  if (requireSuper)
4274  {
4275  if (!superuser())
4276  ereport(ERROR,
4277  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
4278  errmsg("must be superuser to alter a type")));
4279  }
4280  else
4281  {
4282  if (!pg_type_ownercheck(typeOid, GetUserId()))
4284  }
4285 
4286  /*
4287  * We disallow all forms of ALTER TYPE SET on types that aren't plain base
4288  * types. It would for example be highly unsafe, not to mention
4289  * pointless, to change the send/receive functions for a composite type.
4290  * Moreover, pg_dump has no support for changing these properties on
4291  * non-base types. We might weaken this someday, but not now.
4292  *
4293  * Note: if you weaken this enough to allow composite types, be sure to
4294  * adjust the GenerateTypeDependencies call in AlterTypeRecurse.
4295  */
4296  if (typForm->typtype != TYPTYPE_BASE)
4297  ereport(ERROR,
4298  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4299  errmsg("%s is not a base type",
4300  format_type_be(typeOid))));
4301 
4302  /*
4303  * For the same reasons, don't allow direct alteration of array types.
4304  */
4305  if (IsTrueArrayType(typForm))
4306  ereport(ERROR,
4307  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4308  errmsg("%s is not a base type",
4309  format_type_be(typeOid))));
4310 
4311  /* OK, recursively update this type and any arrays/domains over it */
4312  AlterTypeRecurse(typeOid, false, tup, catalog, &atparams);
4313 
4314  /* Clean up */
4315  ReleaseSysCache(tup);
4316 
4317  table_close(catalog, RowExclusiveLock);
4318 
4319  ObjectAddressSet(address, TypeRelationId, typeOid);
4320 
4321  return address;
4322 }
@ ACLCHECK_NOT_OWNER
Definition: acl.h:184
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:5197
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3831
List * defGetQualifiedName(DefElem *def)
Definition: define.c:220
char * defGetString(DefElem *def)
Definition: define.c:49
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
int a
Definition: isn.c:69
Oid GetUserId(void)
Definition: miscinit.c:491
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
Oid typeTypeId(Type tp)
Definition: parse_type.c:590
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
List * options
Definition: parsenodes.h:3477
List * typeName
Definition: parsenodes.h:3476
char * defname
Definition: parsenodes.h:766
Node * arg
Definition: parsenodes.h:767
bool superuser(void)
Definition: superuser.c:46
static Oid findTypeReceiveFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2039
static void AlterTypeRecurse(Oid typeOid, bool isImplicitArray, HeapTuple tup, Relation catalog, AlterTypeRecurseParams *atparams)
Definition: typecmds.c:4348
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2196
static Oid findTypeSendFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2093
static Oid findTypeSubscriptingFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2223
static Oid findTypeTypmodoutFunction(List *procname)
Definition: typecmds.c:2162
static Oid findTypeTypmodinFunction(List *procname)
Definition: typecmds.c:2128

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(), ObjectAddressSet, AlterTypeStmt::options, pg_strcasecmp(), pg_type_ownercheck(), AlterTypeRecurseParams::receiveOid, ReleaseSysCache(), RowExclusiveLock, AlterTypeRecurseParams::sendOid, AlterTypeRecurseParams::storage, AlterTypeRecurseParams::subscriptOid, superuser(), table_close(), table_open(), AlterTypeStmt::typeName, 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 3879 of file typecmds.c.

3881 {
3882  TypeName *typename;
3883  Oid typeOid;
3884  Oid nspOid;
3885  Oid oldNspOid;
3886  ObjectAddresses *objsMoved;
3887  ObjectAddress myself;
3888 
3889  /* Make a TypeName so we can use standard type lookup machinery */
3890  typename = makeTypeNameFromNameList(names);
3891  typeOid = typenameTypeId(NULL, typename);
3892 
3893  /* Don't allow ALTER DOMAIN on a type */
3894  if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3895  ereport(ERROR,
3896  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3897  errmsg("%s is not a domain",
3898  format_type_be(typeOid))));
3899 
3900  /* get schema OID and check its permissions */
3901  nspOid = LookupCreationNamespace(newschema);
3902 
3903  objsMoved = new_object_addresses();
3904  oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3905  free_object_addresses(objsMoved);
3906 
3907  if (oldschema)
3908  *oldschema = oldNspOid;
3909 
3910  ObjectAddressSet(myself, TypeRelationId, typeOid);
3911 
3912  return myself;
3913 }
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2447
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2742
char get_typtype(Oid typid)
Definition: lsyscache.c:2586
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2982
@ OBJECT_DOMAIN
Definition: parsenodes.h:2147
Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: typecmds.c:3916

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,
ObjectAddresses objsMoved 
)

Definition at line 3916 of file typecmds.c.

3917 {
3918  Oid elemOid;
3919 
3920  /* check permissions on type */
3921  if (!pg_type_ownercheck(typeOid, GetUserId()))
3923 
3924  /* don't allow direct alteration of array types */
3925  elemOid = get_element_type(typeOid);
3926  if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3927  ereport(ERROR,
3928  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3929  errmsg("cannot alter array type %s",
3930  format_type_be(typeOid)),
3931  errhint("You can alter type %s, which will alter the array type as well.",
3932  format_type_be(elemOid))));
3933 
3934  /* and do the work */
3935  return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3936 }
#define OidIsValid(objectId)
Definition: c.h:721
int errhint(const char *fmt,...)
Definition: elog.c:1151
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2716
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2744
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3954

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

Referenced by AlterObjectNamespace_oid(), and AlterTypeNamespace().

◆ AlterTypeNamespaceInternal()

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

Definition at line 3954 of file typecmds.c.

3958 {
3959  Relation rel;
3960  HeapTuple tup;
3961  Form_pg_type typform;
3962  Oid oldNspOid;
3963  Oid arrayOid;
3964  bool isCompositeType;
3965  ObjectAddress thisobj;
3966 
3967  /*
3968  * Make sure we haven't moved this object previously.
3969  */
3970  thisobj.classId = TypeRelationId;
3971  thisobj.objectId = typeOid;
3972  thisobj.objectSubId = 0;
3973 
3974  if (object_address_present(&thisobj, objsMoved))
3975  return InvalidOid;
3976 
3977  rel = table_open(TypeRelationId, RowExclusiveLock);
3978 
3979  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3980  if (!HeapTupleIsValid(tup))
3981  elog(ERROR, "cache lookup failed for type %u", typeOid);
3982  typform = (Form_pg_type) GETSTRUCT(tup);
3983 
3984  oldNspOid = typform->typnamespace;
3985  arrayOid = typform->typarray;
3986 
3987  /* If the type is already there, we scan skip these next few checks. */
3988  if (oldNspOid != nspOid)
3989  {
3990  /* common checks on switching namespaces */
3991  CheckSetNamespace(oldNspOid, nspOid);
3992 
3993  /* check for duplicate name (more friendly than unique-index failure) */
3995  NameGetDatum(&typform->typname),
3996  ObjectIdGetDatum(nspOid)))
3997  ereport(ERROR,
3999  errmsg("type \"%s\" already exists in schema \"%s\"",
4000  NameStr(typform->typname),
4001  get_namespace_name(nspOid))));
4002  }
4003 
4004  /* Detect whether type is a composite type (but not a table rowtype) */
4005  isCompositeType =
4006  (typform->typtype == TYPTYPE_COMPOSITE &&
4007  get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
4008 
4009  /* Enforce not-table-type if requested */
4010  if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
4011  errorOnTableType)
4012  ereport(ERROR,
4013  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4014  errmsg("%s is a table's row type",
4015  format_type_be(typeOid)),
4016  errhint("Use ALTER TABLE instead.")));
4017 
4018  if (oldNspOid != nspOid)
4019  {
4020  /* OK, modify the pg_type row */
4021 
4022  /* tup is a copy, so we can scribble directly on it */
4023  typform->typnamespace = nspOid;
4024 
4025  CatalogTupleUpdate(rel, &tup->t_self, tup);
4026  }
4027 
4028  /*
4029  * Composite types have pg_class entries.
4030  *
4031  * We need to modify the pg_class tuple as well to reflect the change of
4032  * schema.
4033  */
4034  if (isCompositeType)
4035  {
4036  Relation classRel;
4037 
4038  classRel = table_open(RelationRelationId, RowExclusiveLock);
4039 
4040  AlterRelationNamespaceInternal(classRel, typform->typrelid,
4041  oldNspOid, nspOid,
4042  false, objsMoved);
4043 
4044  table_close(classRel, RowExclusiveLock);
4045 
4046  /*
4047  * Check for constraints associated with the composite type (we don't
4048  * currently support this, but probably will someday).
4049  */
4050  AlterConstraintNamespaces(typform->typrelid, oldNspOid,
4051  nspOid, false, objsMoved);
4052  }
4053  else
4054  {
4055  /* If it's a domain, it might have constraints */
4056  if (typform->typtype == TYPTYPE_DOMAIN)
4057  AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
4058  objsMoved);
4059  }
4060 
4061  /*
4062  * Update dependency on schema, if any --- a table rowtype has not got
4063  * one, and neither does an implicit array.
4064  */
4065  if (oldNspOid != nspOid &&
4066  (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
4067  !isImplicitArray)
4068  if (changeDependencyFor(TypeRelationId, typeOid,
4069  NamespaceRelationId, oldNspOid, nspOid) != 1)
4070  elog(ERROR, "failed to change schema dependency for type %s",
4071  format_type_be(typeOid));
4072 
4073  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
4074 
4075  heap_freetuple(tup);
4076 
4078 
4079  add_exact_object_address(&thisobj, objsMoved);
4080 
4081  /* Recursively alter the associated array type, if any */
4082  if (OidIsValid(arrayOid))
4083  AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
4084 
4085  return oldNspOid;
4086 }
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2562
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2502
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3326
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1984
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:3013
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:399
#define NameGetDatum(X)
Definition: postgres.h:639
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
@ TYPENAMENSP
Definition: syscache.h:113
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:190
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:16497

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, NameGetDatum, NameStr, object_address_present(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, RowExclusiveLock, SearchSysCacheCopy1, SearchSysCacheExists2, HeapTupleData::t_self, table_close(), table_open(), TYPENAMENSP, and TYPEOID.

Referenced by AlterTableNamespaceInternal(), and AlterTypeNamespace_oid().

◆ AlterTypeOwner()

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

Definition at line 3676 of file typecmds.c.

3677 {
3678  TypeName *typename;
3679  Oid typeOid;
3680  Relation rel;
3681  HeapTuple tup;
3682  HeapTuple newtup;
3683  Form_pg_type typTup;
3684  AclResult aclresult;
3685  ObjectAddress address;
3686 
3687  rel = table_open(TypeRelationId, RowExclusiveLock);
3688 
3689  /* Make a TypeName so we can use standard type lookup machinery */
3690  typename = makeTypeNameFromNameList(names);
3691 
3692  /* Use LookupTypeName here so that shell types can be processed */
3693  tup = LookupTypeName(NULL, typename, NULL, false);
3694  if (tup == NULL)
3695  ereport(ERROR,
3696  (errcode(ERRCODE_UNDEFINED_OBJECT),
3697  errmsg("type \"%s\" does not exist",
3698  TypeNameToString(typename))));
3699  typeOid = typeTypeId(tup);
3700 
3701  /* Copy the syscache entry so we can scribble on it below */
3702  newtup = heap_copytuple(tup);
3703  ReleaseSysCache(tup);
3704  tup = newtup;
3705  typTup = (Form_pg_type) GETSTRUCT(tup);
3706 
3707  /* Don't allow ALTER DOMAIN on a type */
3708  if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3709  ereport(ERROR,
3710  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3711  errmsg("%s is not a domain",
3712  format_type_be(typeOid))));
3713 
3714  /*
3715  * If it's a composite type, we need to check that it really is a
3716  * free-standing composite type, and not a table's rowtype. We want people
3717  * to use ALTER TABLE not ALTER TYPE for that case.
3718  */
3719  if (typTup->typtype == TYPTYPE_COMPOSITE &&
3720  get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3721  ereport(ERROR,
3722  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3723  errmsg("%s is a table's row type",
3724  format_type_be(typeOid)),
3725  errhint("Use ALTER TABLE instead.")));
3726 
3727  /* don't allow direct alteration of array types, either */
3728  if (IsTrueArrayType(typTup))
3729  ereport(ERROR,
3730  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3731  errmsg("cannot alter array type %s",
3732  format_type_be(typeOid)),
3733  errhint("You can alter type %s, which will alter the array type as well.",
3734  format_type_be(typTup->typelem))));
3735 
3736  /*
3737  * If the new owner is the same as the existing owner, consider the
3738  * command to have succeeded. This is for dump restoration purposes.
3739  */
3740  if (typTup->typowner != newOwnerId)
3741  {
3742  /* Superusers can always do it */
3743  if (!superuser())
3744  {
3745  /* Otherwise, must be owner of the existing object */
3746  if (!pg_type_ownercheck(typTup->oid, GetUserId()))
3748 
3749  /* Must be able to become new owner */
3750  check_is_member_of_role(GetUserId(), newOwnerId);
3751 
3752  /* New owner must have CREATE privilege on namespace */
3753  aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3754  newOwnerId,
3755  ACL_CREATE);
3756  if (aclresult != ACLCHECK_OK)
3757  aclcheck_error(aclresult, OBJECT_SCHEMA,
3758  get_namespace_name(typTup->typnamespace));
3759  }
3760 
3761  AlterTypeOwner_oid(typeOid, newOwnerId, true);
3762  }
3763 
3764  ObjectAddressSet(address, TypeRelationId, typeOid);
3765 
3766  /* Clean up */
3768 
3769  return address;
3770 }
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4977
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:5109
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3512
Type LookupTypeName(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, bool missing_ok)
Definition: parse_type.c:38
@ OBJECT_SCHEMA
Definition: parsenodes.h:2171
#define ACL_CREATE
Definition: parsenodes.h:91
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition: typecmds.c:3784

References ACL_CREATE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTypeOwner_oid(), check_is_member_of_role(), ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), get_namespace_name(), get_rel_relkind(), GETSTRUCT, GetUserId(), heap_copytuple(), LookupTypeName(), makeTypeNameFromNameList(), OBJECT_DOMAIN, OBJECT_SCHEMA, ObjectAddressSet, pg_namespace_aclcheck(), pg_type_ownercheck(), 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 3784 of file typecmds.c.

3785 {
3786  Relation rel;
3787  HeapTuple tup;
3788  Form_pg_type typTup;
3789 
3790  rel = table_open(TypeRelationId, RowExclusiveLock);
3791 
3792  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3793  if (!HeapTupleIsValid(tup))
3794  elog(ERROR, "cache lookup failed for type %u", typeOid);
3795  typTup = (Form_pg_type) GETSTRUCT(tup);
3796 
3797  /*
3798  * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3799  * the pg_class entry properly. That will call back to
3800  * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3801  */
3802  if (typTup->typtype == TYPTYPE_COMPOSITE)
3803  ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3804  else
3805  AlterTypeOwnerInternal(typeOid, newOwnerId);
3806 
3807  /* Update owner dependency reference */
3808  if (hasDependEntry)
3809  changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3810 
3811  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3812 
3813  ReleaseSysCache(tup);
3815 }
#define AccessExclusiveLock
Definition: lockdefs.h:43
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:312
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:13670
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3824

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

Referenced by AlterTypeOwner(), and shdepReassignOwned().

◆ AlterTypeOwnerInternal()

void AlterTypeOwnerInternal ( Oid  typeOid,
Oid  newOwnerId 
)

Definition at line 3824 of file typecmds.c.

3825 {
3826  Relation rel;
3827  HeapTuple tup;
3828  Form_pg_type typTup;
3829  Datum repl_val[Natts_pg_type];
3830  bool repl_null[Natts_pg_type];
3831  bool repl_repl[Natts_pg_type];
3832  Acl *newAcl;
3833  Datum aclDatum;
3834  bool isNull;
3835 
3836  rel = table_open(TypeRelationId, RowExclusiveLock);
3837 
3838  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3839  if (!HeapTupleIsValid(tup))
3840  elog(ERROR, "cache lookup failed for type %u", typeOid);
3841  typTup = (Form_pg_type) GETSTRUCT(tup);
3842 
3843  memset(repl_null, false, sizeof(repl_null));
3844  memset(repl_repl, false, sizeof(repl_repl));
3845 
3846  repl_repl[Anum_pg_type_typowner - 1] = true;
3847  repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
3848 
3849  aclDatum = heap_getattr(tup,
3850  Anum_pg_type_typacl,
3851  RelationGetDescr(rel),
3852  &isNull);
3853  /* Null ACLs do not require changes */
3854  if (!isNull)
3855  {
3856  newAcl = aclnewowner(DatumGetAclP(aclDatum),
3857  typTup->typowner, newOwnerId);
3858  repl_repl[Anum_pg_type_typacl - 1] = true;
3859  repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3860  }
3861 
3862  tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3863  repl_repl);
3864 
3865  CatalogTupleUpdate(rel, &tup->t_self, tup);
3866 
3867  /* If it has an array type, update that too */
3868  if (OidIsValid(typTup->typarray))
3869  AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
3870 
3871  /* Clean up */
3873 }
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1052
#define DatumGetAclP(X)
Definition: acl.h:120
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:788
#define PointerGetDatum(X)
Definition: postgres.h:600

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

Referenced by AlterTypeOwner_oid(), and ATExecChangeOwner().

◆ AssignTypeArrayOid()

Oid AssignTypeArrayOid ( void  )

Definition at line 2398 of file typecmds.c.

2399 {
2400  Oid type_array_oid;
2401 
2402  /* Use binary-upgrade override for pg_type.typarray? */
2403  if (IsBinaryUpgrade)
2404  {
2406  ereport(ERROR,
2407  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2408  errmsg("pg_type array OID value not set when in binary upgrade mode")));
2409 
2410  type_array_oid = binary_upgrade_next_array_pg_type_oid;
2412  }
2413  else
2414  {
2415  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2416 
2417  type_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2418  Anum_pg_type_oid);
2419  table_close(pg_type, AccessShareLock);
2420  }
2421 
2422  return type_array_oid;
2423 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:391
bool IsBinaryUpgrade
Definition: globals.c:114
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 2464 of file typecmds.c.

2465 {
2466  Oid type_multirange_array_oid;
2467 
2468  /* Use binary-upgrade override for pg_type.oid? */
2469  if (IsBinaryUpgrade)
2470  {
2472  ereport(ERROR,
2473  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2474  errmsg("pg_type multirange array OID value not set when in binary upgrade mode")));
2475 
2476  type_multirange_array_oid = binary_upgrade_next_mrng_array_pg_type_oid;
2478  }
2479  else
2480  {
2481  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2482 
2483  type_multirange_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2484  Anum_pg_type_oid);
2485  table_close(pg_type, AccessShareLock);
2486  }
2487 
2488  return type_multirange_array_oid;
2489 }
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 2431 of file typecmds.c.

2432 {
2433  Oid type_multirange_oid;
2434 
2435  /* Use binary-upgrade override for pg_type.oid? */
2436  if (IsBinaryUpgrade)
2437  {
2439  ereport(ERROR,
2440  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2441  errmsg("pg_type multirange OID value not set when in binary upgrade mode")));
2442 
2443  type_multirange_oid = binary_upgrade_next_mrng_pg_type_oid;
2445  }
2446  else
2447  {
2448  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2449 
2450  type_multirange_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2451  Anum_pg_type_oid);
2452  table_close(pg_type, AccessShareLock);
2453  }
2454 
2455  return type_multirange_oid;
2456 }
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 3422 of file typecmds.c.

3423 {
3424  Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
3425 
3426  /* Check that this is actually a domain */
3427  if (typTup->typtype != TYPTYPE_DOMAIN)
3428  ereport(ERROR,
3429  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3430  errmsg("%s is not a domain",
3431  format_type_be(typTup->oid))));
3432 
3433  /* Permission check: must own type */
3434  if (!pg_type_ownercheck(typTup->oid, GetUserId()))
3436 }

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

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

◆ DefineCompositeType()

ObjectAddress DefineCompositeType ( RangeVar typevar,
List coldeflist 
)

Definition at line 2506 of file typecmds.c.

2507 {
2508  CreateStmt *createStmt = makeNode(CreateStmt);
2509  Oid old_type_oid;
2510  Oid typeNamespace;
2511  ObjectAddress address;
2512 
2513  /*
2514  * now set the parameters for keys/inheritance etc. All of these are
2515  * uninteresting for composite types...
2516  */
2517  createStmt->relation = typevar;
2518  createStmt->tableElts = coldeflist;
2519  createStmt->inhRelations = NIL;
2520  createStmt->constraints = NIL;
2521  createStmt->options = NIL;
2522  createStmt->oncommit = ONCOMMIT_NOOP;
2523  createStmt->tablespacename = NULL;
2524  createStmt->if_not_exists = false;
2525 
2526  /*
2527  * Check for collision with an existing type name. If there is one and
2528  * it's an autogenerated array, we can rename it out of the way. This
2529  * check is here mainly to get a better error message about a "type"
2530  * instead of below about a "relation".
2531  */
2532  typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2533  NoLock, NULL);
2534  RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2535  old_type_oid =
2536  GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
2537  CStringGetDatum(createStmt->relation->relname),
2538  ObjectIdGetDatum(typeNamespace));
2539  if (OidIsValid(old_type_oid))
2540  {
2541  if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2542  ereport(ERROR,
2544  errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2545  }
2546 
2547  /*
2548  * Finally create the relation. This also creates the type.
2549  */
2550  DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2551  NULL);
2552 
2553  return address;
2554 }
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:536
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition: namespace.c:643
#define makeNode(_type_)
Definition: nodes.h:622
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:856
@ ONCOMMIT_NOOP
Definition: primnodes.h:49
List * tableElts
Definition: parsenodes.h:2532
OnCommitAction oncommit
Definition: parsenodes.h:2540
List * options
Definition: parsenodes.h:2539
bool if_not_exists
Definition: parsenodes.h:2543
List * inhRelations
Definition: parsenodes.h:2533
RangeVar * relation
Definition: parsenodes.h:2531
char * tablespacename
Definition: parsenodes.h:2541
List * constraints
Definition: parsenodes.h:2538
char * relname
Definition: primnodes.h:74
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:199
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:658

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, CreateStmt::tablespacename, and TYPENAMENSP.

Referenced by ProcessUtilitySlow().

◆ DefineDomain()

ObjectAddress DefineDomain ( CreateDomainStmt stmt)

Definition at line 693 of file typecmds.c.

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

References ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, TypeName::arrayBounds, AssignTypeArrayOid(), CreateDomainStmt::collClause, CollateClause::collname, CommandCounterIncrement(), CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_NOTNULL, CONSTR_NULL, CONSTR_PRIMARY, CONSTR_UNIQUE, CreateDomainStmt::constraints, Constraint::contype, cookDefault(), CStringGetDatum, deparse_expression(), domainAddConstraint(), CreateDomainStmt::domainname, 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_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, pfree(), pg_namespace_aclcheck(), pg_type_aclcheck(), QualifiedNameGetCreationNamespace(), Constraint::raw_expr, ReleaseSysCache(), SysCacheGetAttr(), TextDatumGetCString, TypeCreate(), CreateDomainStmt::typeName, TYPENAMENSP, TypeNameToString(), typenameType(), and TYPEOID.

Referenced by ProcessUtilitySlow().

◆ DefineEnum()

ObjectAddress DefineEnum ( CreateEnumStmt stmt)

Definition at line 1137 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

◆ DefineRange()

ObjectAddress DefineRange ( ParseState pstate,
CreateRangeStmt stmt 
)

Definition at line 1336 of file typecmds.c.

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

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_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, CreateRangeStmt::params, pfree(), pg_namespace_aclcheck(), PG_USED_FOR_ASSERTS_ONLY, QualifiedNameGetCreationNamespace(), RangeCreate(), type_is_collatable(), TypeCreate(), CreateRangeStmt::typeName, TYPENAMENSP, and typenameTypeId().

Referenced by ProcessUtilitySlow().

◆ DefineType()

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

Definition at line 148 of file typecmds.c.

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

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_FUNCTION, OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, parser_errposition(), pfree(), pg_namespace_aclcheck(), pg_proc_ownercheck(), pg_strcasecmp(), QualifiedNameGetCreationNamespace(), ReleaseSysCache(), superuser(), TypeCreate(), TYPENAMENSP, typenameType(), typenameTypeId(), TypeShellMake(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ RemoveTypeById()

void RemoveTypeById ( Oid  typeOid)

Definition at line 653 of file typecmds.c.

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

Referenced by doDeletion().

◆ RenameType()

ObjectAddress RenameType ( RenameStmt stmt)

Definition at line 3599 of file typecmds.c.

3600 {
3601  List *names = castNode(List, stmt->object);
3602  const char *newTypeName = stmt->newname;
3603  TypeName *typename;
3604  Oid typeOid;
3605  Relation rel;
3606  HeapTuple tup;
3607  Form_pg_type typTup;
3608  ObjectAddress address;
3609 
3610  /* Make a TypeName so we can use standard type lookup machinery */
3611  typename = makeTypeNameFromNameList(names);
3612  typeOid = typenameTypeId(NULL, typename);
3613 
3614  /* Look up the type in the type table */
3615  rel = table_open(TypeRelationId, RowExclusiveLock);
3616 
3617  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3618  if (!HeapTupleIsValid(tup))
3619  elog(ERROR, "cache lookup failed for type %u", typeOid);
3620  typTup = (Form_pg_type) GETSTRUCT(tup);
3621 
3622  /* check permissions on type */
3623  if (!pg_type_ownercheck(typeOid, GetUserId()))
3625 
3626  /* ALTER DOMAIN used on a non-domain? */
3627  if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3628  ereport(ERROR,
3629  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3630  errmsg("%s is not a domain",
3631  format_type_be(typeOid))));
3632 
3633  /*
3634  * If it's a composite type, we need to check that it really is a
3635  * free-standing composite type, and not a table's rowtype. We want people
3636  * to use ALTER TABLE not ALTER TYPE for that case.
3637  */
3638  if (typTup->typtype == TYPTYPE_COMPOSITE &&
3639  get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3640  ereport(ERROR,
3641  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3642  errmsg("%s is a table's row type",
3643  format_type_be(typeOid)),
3644  errhint("Use ALTER TABLE instead.")));
3645 
3646  /* don't allow direct alteration of array types, either */
3647  if (IsTrueArrayType(typTup))
3648  ereport(ERROR,
3649  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3650  errmsg("cannot alter array type %s",
3651  format_type_be(typeOid)),
3652  errhint("You can alter type %s, which will alter the array type as well.",
3653  format_type_be(typTup->typelem))));
3654 
3655  /*
3656  * If type is composite we need to rename associated pg_class entry too.
3657  * RenameRelationInternal will call RenameTypeInternal automatically.
3658  */
3659  if (typTup->typtype == TYPTYPE_COMPOSITE)
3660  RenameRelationInternal(typTup->typrelid, newTypeName, false, false);
3661  else
3662  RenameTypeInternal(typeOid, newTypeName,
3663  typTup->typnamespace);
3664 
3665  ObjectAddressSet(address, TypeRelationId, typeOid);
3666  /* Clean up */
3668 
3669  return address;
3670 }
#define castNode(_type_, nodeptr)
Definition: nodes.h:643
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:741
ObjectType renameType
Definition: parsenodes.h:3406
char * newname
Definition: parsenodes.h:3412
Node * object
Definition: parsenodes.h:3409
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index)
Definition: tablecmds.c:3846

References aclcheck_error_type(), ACLCHECK_NOT_OWNER, castNode, elog(), ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), get_rel_relkind(), GETSTRUCT, GetUserId(), HeapTupleIsValid, makeTypeNameFromNameList(), RenameStmt::newname, RenameStmt::object, OBJECT_DOMAIN, ObjectAddressSet, ObjectIdGetDatum, pg_type_ownercheck(), RenameRelationInternal(), RenameStmt::renameType, RenameTypeInternal(), RowExclusiveLock, SearchSysCacheCopy1, table_close(), table_open(), typenameTypeId(), and TYPEOID.

Referenced by ExecRenameStmt().