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

Go to the source code of this file.

Data Structures

struct  RelToCheck
 
struct  AlterTypeRecurseParams
 

Functions

static void makeRangeConstructors (const char *name, Oid namespace, Oid rangeOid, Oid subtype)
 
static void makeMultirangeConstructors (const char *name, Oid namespace, Oid multirangeOid, Oid rangeOid, Oid rangeArrayOid, Oid *castFuncOid)
 
static Oid findTypeInputFunction (List *procname, Oid typeOid)
 
static Oid findTypeOutputFunction (List *procname, Oid typeOid)
 
static Oid findTypeReceiveFunction (List *procname, Oid typeOid)
 
static Oid findTypeSendFunction (List *procname, Oid typeOid)
 
static Oid findTypeTypmodinFunction (List *procname)
 
static Oid findTypeTypmodoutFunction (List *procname)
 
static Oid findTypeAnalyzeFunction (List *procname, Oid typeOid)
 
static Oid findTypeSubscriptingFunction (List *procname, Oid typeOid)
 
static Oid findRangeSubOpclass (List *opcname, Oid subtype)
 
static Oid findRangeCanonicalFunction (List *procname, Oid typeOid)
 
static Oid findRangeSubtypeDiffFunction (List *procname, Oid subtype)
 
static void validateDomainCheckConstraint (Oid domainoid, const char *ccbin)
 
static void validateDomainNotNullConstraint (Oid domainoid)
 
static Listget_rels_with_domain (Oid domainOid, LOCKMODE lockmode)
 
static void checkEnumOwner (HeapTuple tup)
 
static char * domainAddCheckConstraint (Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
 
static Nodereplace_domain_constraint_value (ParseState *pstate, ColumnRef *cref)
 
static void domainAddNotNullConstraint (Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
 
static void AlterTypeRecurse (Oid typeOid, bool isImplicitArray, HeapTuple tup, Relation catalog, AlterTypeRecurseParams *atparams)
 
ObjectAddress DefineType (ParseState *pstate, List *names, List *parameters)
 
void RemoveTypeById (Oid typeOid)
 
ObjectAddress DefineDomain (CreateDomainStmt *stmt)
 
ObjectAddress DefineEnum (CreateEnumStmt *stmt)
 
ObjectAddress AlterEnum (AlterEnumStmt *stmt)
 
ObjectAddress DefineRange (ParseState *pstate, CreateRangeStmt *stmt)
 
Oid AssignTypeArrayOid (void)
 
Oid AssignTypeMultirangeOid (void)
 
Oid AssignTypeMultirangeArrayOid (void)
 
ObjectAddress DefineCompositeType (RangeVar *typevar, List *coldeflist)
 
ObjectAddress AlterDomainDefault (List *names, Node *defaultRaw)
 
ObjectAddress AlterDomainNotNull (List *names, bool notNull)
 
ObjectAddress AlterDomainDropConstraint (List *names, const char *constrName, DropBehavior behavior, bool missing_ok)
 
ObjectAddress AlterDomainAddConstraint (List *names, Node *newConstraint, ObjectAddress *constrAddr)
 
ObjectAddress AlterDomainValidateConstraint (List *names, const char *constrName)
 
void checkDomainOwner (HeapTuple tup)
 
ObjectAddress RenameType (RenameStmt *stmt)
 
ObjectAddress AlterTypeOwner (List *names, Oid newOwnerId, ObjectType objecttype)
 
void AlterTypeOwner_oid (Oid typeOid, Oid newOwnerId, bool hasDependEntry)
 
void AlterTypeOwnerInternal (Oid typeOid, Oid newOwnerId)
 
ObjectAddress AlterTypeNamespace (List *names, const char *newschema, ObjectType objecttype, Oid *oldschema)
 
Oid AlterTypeNamespace_oid (Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
 
Oid AlterTypeNamespaceInternal (Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
 
ObjectAddress AlterType (AlterTypeStmt *stmt)
 

Variables

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

Function Documentation

◆ AlterDomainAddConstraint()

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

Definition at line 2897 of file typecmds.c.

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

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

Referenced by ATExecCmd(), and ProcessUtilitySlow().

◆ AlterDomainDefault()

ObjectAddress AlterDomainDefault ( List names,
Node defaultRaw 
)

Definition at line 2576 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterDomainDropConstraint()

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

Definition at line 2791 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterDomainNotNull()

ObjectAddress AlterDomainNotNull ( List names,
bool  notNull 
)

Definition at line 2705 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterDomainValidateConstraint()

ObjectAddress AlterDomainValidateConstraint ( List names,
const char *  constrName 
)

Definition at line 3037 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterEnum()

ObjectAddress AlterEnum ( AlterEnumStmt stmt)

Definition at line 1271 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterType()

ObjectAddress AlterType ( AlterTypeStmt stmt)

Definition at line 4277 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterTypeNamespace()

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

Definition at line 4057 of file typecmds.c.

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

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

4095 {
4096  Oid elemOid;
4097 
4098  /* check permissions on type */
4099  if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
4101 
4102  /* don't allow direct alteration of array types */
4103  elemOid = get_element_type(typeOid);
4104  if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
4105  ereport(ERROR,
4106  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
4107  errmsg("cannot alter array type %s",
4108  format_type_be(typeOid)),
4109  errhint("You can alter type %s, which will alter the array type as well.",
4110  format_type_be(elemOid))));
4111 
4112  /* and do the work */
4113  return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
4114 }
#define OidIsValid(objectId)
Definition: c.h:775
int errhint(const char *fmt,...)
Definition: elog.c:1319
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2759
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2787
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:4132

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

Referenced by AlterObjectNamespace_oid(), and AlterTypeNamespace().

◆ AlterTypeNamespaceInternal()

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

Definition at line 4132 of file typecmds.c.

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

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

Referenced by AlterTableNamespaceInternal(), and AlterTypeNamespace_oid().

◆ AlterTypeOwner()

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

Definition at line 3824 of file typecmds.c.

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

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

Referenced by ExecAlterOwnerStmt().

◆ AlterTypeOwner_oid()

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

Definition at line 3949 of file typecmds.c.

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

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

Referenced by AlterTypeOwner(), and shdepReassignOwned().

◆ AlterTypeOwnerInternal()

void AlterTypeOwnerInternal ( Oid  typeOid,
Oid  newOwnerId 
)

Definition at line 3989 of file typecmds.c.

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

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

Referenced by AlterTypeOwner_oid(), and ATExecChangeOwner().

◆ AlterTypeRecurse()

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

Definition at line 4528 of file typecmds.c.

4531 {
4532  Datum values[Natts_pg_type];
4533  bool nulls[Natts_pg_type];
4534  bool replaces[Natts_pg_type];
4535  HeapTuple newtup;
4536  SysScanDesc scan;
4537  ScanKeyData key[1];
4538  HeapTuple domainTup;
4539 
4540  /* Since this function recurses, it could be driven to stack overflow */
4542 
4543  /* Update the current type's tuple */
4544  memset(values, 0, sizeof(values));
4545  memset(nulls, 0, sizeof(nulls));
4546  memset(replaces, 0, sizeof(replaces));
4547 
4548  if (atparams->updateStorage)
4549  {
4550  replaces[Anum_pg_type_typstorage - 1] = true;
4551  values[Anum_pg_type_typstorage - 1] = CharGetDatum(atparams->storage);
4552  }
4553  if (atparams->updateReceive)
4554  {
4555  replaces[Anum_pg_type_typreceive - 1] = true;
4556  values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(atparams->receiveOid);
4557  }
4558  if (atparams->updateSend)
4559  {
4560  replaces[Anum_pg_type_typsend - 1] = true;
4561  values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(atparams->sendOid);
4562  }
4563  if (atparams->updateTypmodin)
4564  {
4565  replaces[Anum_pg_type_typmodin - 1] = true;
4566  values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(atparams->typmodinOid);
4567  }
4568  if (atparams->updateTypmodout)
4569  {
4570  replaces[Anum_pg_type_typmodout - 1] = true;
4571  values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(atparams->typmodoutOid);
4572  }
4573  if (atparams->updateAnalyze)
4574  {
4575  replaces[Anum_pg_type_typanalyze - 1] = true;
4576  values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(atparams->analyzeOid);
4577  }
4578  if (atparams->updateSubscript)
4579  {
4580  replaces[Anum_pg_type_typsubscript - 1] = true;
4581  values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(atparams->subscriptOid);
4582  }
4583 
4584  newtup = heap_modify_tuple(tup, RelationGetDescr(catalog),
4585  values, nulls, replaces);
4586 
4587  CatalogTupleUpdate(catalog, &newtup->t_self, newtup);
4588 
4589  /* Rebuild dependencies for this type */
4590  GenerateTypeDependencies(newtup,
4591  catalog,
4592  NULL, /* don't have defaultExpr handy */
4593  NULL, /* don't have typacl handy */
4594  0, /* we rejected composite types above */
4595  isImplicitArray, /* it might be an array */
4596  isImplicitArray, /* dependent iff it's array */
4597  false, /* don't touch extension membership */
4598  true);
4599 
4600  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
4601 
4602  /*
4603  * Arrays inherit their base type's typmodin and typmodout, but none of
4604  * the other properties we're concerned with here. Recurse to the array
4605  * type if needed.
4606  */
4607  if (!isImplicitArray &&
4608  (atparams->updateTypmodin || atparams->updateTypmodout))
4609  {
4610  Oid arrtypoid = ((Form_pg_type) GETSTRUCT(newtup))->typarray;
4611 
4612  if (OidIsValid(arrtypoid))
4613  {
4614  HeapTuple arrtup;
4615  AlterTypeRecurseParams arrparams;
4616 
4617  arrtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrtypoid));
4618  if (!HeapTupleIsValid(arrtup))
4619  elog(ERROR, "cache lookup failed for type %u", arrtypoid);
4620 
4621  memset(&arrparams, 0, sizeof(arrparams));
4622  arrparams.updateTypmodin = atparams->updateTypmodin;
4623  arrparams.updateTypmodout = atparams->updateTypmodout;
4624  arrparams.typmodinOid = atparams->typmodinOid;
4625  arrparams.typmodoutOid = atparams->typmodoutOid;
4626 
4627  AlterTypeRecurse(arrtypoid, true, arrtup, catalog, &arrparams);
4628 
4629  ReleaseSysCache(arrtup);
4630  }
4631  }
4632 
4633  /*
4634  * Now we need to recurse to domains. However, some properties are not
4635  * inherited by domains, so clear the update flags for those.
4636  */
4637  atparams->updateReceive = false; /* domains use F_DOMAIN_RECV */
4638  atparams->updateTypmodin = false; /* domains don't have typmods */
4639  atparams->updateTypmodout = false;
4640  atparams->updateSubscript = false; /* domains don't have subscriptors */
4641 
4642  /* Skip the scan if nothing remains to be done */
4643  if (!(atparams->updateStorage ||
4644  atparams->updateSend ||
4645  atparams->updateAnalyze))
4646  return;
4647 
4648  /* Search pg_type for possible domains over this type */
4649  ScanKeyInit(&key[0],
4650  Anum_pg_type_typbasetype,
4651  BTEqualStrategyNumber, F_OIDEQ,
4652  ObjectIdGetDatum(typeOid));
4653 
4654  scan = systable_beginscan(catalog, InvalidOid, false,
4655  NULL, 1, key);
4656 
4657  while ((domainTup = systable_getnext(scan)) != NULL)
4658  {
4659  Form_pg_type domainForm = (Form_pg_type) GETSTRUCT(domainTup);
4660 
4661  /*
4662  * Shouldn't have a nonzero typbasetype in a non-domain, but let's
4663  * check
4664  */
4665  if (domainForm->typtype != TYPTYPE_DOMAIN)
4666  continue;
4667 
4668  AlterTypeRecurse(domainForm->oid, false, domainTup, catalog, atparams);
4669  }
4670 
4671  systable_endscan(scan);
4672 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
void check_stack_depth(void)
Definition: postgres.c:3531
static Datum CharGetDatum(char X)
Definition: postgres.h:122

References AlterTypeRecurseParams::analyzeOid, BTEqualStrategyNumber, CatalogTupleUpdate(), CharGetDatum(), check_stack_depth(), elog, ERROR, GenerateTypeDependencies(), GETSTRUCT, heap_modify_tuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHook, sort-test::key, ObjectIdGetDatum(), OidIsValid, AlterTypeRecurseParams::receiveOid, RelationGetDescr, ReleaseSysCache(), ScanKeyInit(), SearchSysCache1(), AlterTypeRecurseParams::sendOid, AlterTypeRecurseParams::storage, AlterTypeRecurseParams::subscriptOid, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, AlterTypeRecurseParams::typmodinOid, AlterTypeRecurseParams::typmodoutOid, AlterTypeRecurseParams::updateAnalyze, AlterTypeRecurseParams::updateReceive, AlterTypeRecurseParams::updateSend, AlterTypeRecurseParams::updateStorage, AlterTypeRecurseParams::updateSubscript, AlterTypeRecurseParams::updateTypmodin, AlterTypeRecurseParams::updateTypmodout, and values.

Referenced by AlterType().

◆ AssignTypeArrayOid()

Oid AssignTypeArrayOid ( void  )

Definition at line 2410 of file typecmds.c.

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

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

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

◆ AssignTypeMultirangeArrayOid()

Oid AssignTypeMultirangeArrayOid ( void  )

Definition at line 2476 of file typecmds.c.

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

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

Referenced by DefineRange().

◆ AssignTypeMultirangeOid()

Oid AssignTypeMultirangeOid ( void  )

Definition at line 2443 of file typecmds.c.

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

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

Referenced by DefineRange().

◆ checkDomainOwner()

void checkDomainOwner ( HeapTuple  tup)

Definition at line 3490 of file typecmds.c.

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

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

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

◆ checkEnumOwner()

static void checkEnumOwner ( HeapTuple  tup)
static

Definition at line 1319 of file typecmds.c.

1320 {
1321  Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1322 
1323  /* Check that this is actually an enum */
1324  if (typTup->typtype != TYPTYPE_ENUM)
1325  ereport(ERROR,
1326  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1327  errmsg("%s is not an enum",
1328  format_type_be(typTup->oid))));
1329 
1330  /* Permission check: must own type */
1331  if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
1333 }

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

Referenced by AlterEnum().

◆ DefineCompositeType()

ObjectAddress DefineCompositeType ( RangeVar typevar,
List coldeflist 
)

Definition at line 2518 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ DefineDomain()

ObjectAddress DefineDomain ( CreateDomainStmt stmt)

Definition at line 697 of file typecmds.c.

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

References ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, AssignTypeArrayOid(), CommandCounterIncrement(), CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_NOTNULL, CONSTR_NULL, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, cookDefault(), CStringGetDatum(), deparse_expression(), domainAddCheckConstraint(), domainAddNotNullConstraint(), elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, format_type_be(), get_collation_oid(), get_namespace_name(), GETSTRUCT, GetSysCacheOid2, GetUserId(), InvalidOid, Constraint::is_no_inherit, IsA, lfirst, list_length(), make_parsestate(), makeArrayTypeName(), moveArrayTypeName(), NIL, nodeTag, nodeToString(), object_aclcheck(), OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum(), OidIsValid, pfree(), QualifiedNameGetCreationNamespace(), Constraint::raw_expr, ReleaseSysCache(), stmt, storage, SysCacheGetAttr(), TextDatumGetCString, TypeCreate(), TypeNameToString(), and typenameType().

Referenced by ProcessUtilitySlow().

◆ DefineEnum()

ObjectAddress DefineEnum ( CreateEnumStmt stmt)

Definition at line 1147 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ DefineRange()

ObjectAddress DefineRange ( ParseState pstate,
CreateRangeStmt stmt 
)

Definition at line 1346 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ DefineType()

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

Definition at line 152 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ domainAddCheckConstraint()

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

Definition at line 3510 of file typecmds.c.

3513 {
3514  Node *expr;
3515  char *ccbin;
3516  ParseState *pstate;
3517  CoerceToDomainValue *domVal;
3518  Oid ccoid;
3519 
3520  Assert(constr->contype == CONSTR_CHECK);
3521 
3522  /*
3523  * Assign or validate constraint name
3524  */
3525  if (constr->conname)
3526  {
3528  domainOid,
3529  constr->conname))
3530  ereport(ERROR,
3532  errmsg("constraint \"%s\" for domain \"%s\" already exists",
3533  constr->conname, domainName)));
3534  }
3535  else
3536  constr->conname = ChooseConstraintName(domainName,
3537  NULL,
3538  "check",
3539  domainNamespace,
3540  NIL);
3541 
3542  /*
3543  * Convert the A_EXPR in raw_expr into an EXPR
3544  */
3545  pstate = make_parsestate(NULL);
3546 
3547  /*
3548  * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
3549  * the expression. Note that it will appear to have the type of the base
3550  * type, not the domain. This seems correct since within the check
3551  * expression, we should not assume the input value can be considered a
3552  * member of the domain.
3553  */
3554  domVal = makeNode(CoerceToDomainValue);
3555  domVal->typeId = baseTypeOid;
3556  domVal->typeMod = typMod;
3557  domVal->collation = get_typcollation(baseTypeOid);
3558  domVal->location = -1; /* will be set when/if used */
3559 
3561  pstate->p_ref_hook_state = (void *) domVal;
3562 
3563  expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
3564 
3565  /*
3566  * Make sure it yields a boolean result.
3567  */
3568  expr = coerce_to_boolean(pstate, expr, "CHECK");
3569 
3570  /*
3571  * Fix up collation information.
3572  */
3573  assign_expr_collations(pstate, expr);
3574 
3575  /*
3576  * Domains don't allow variables (this is probably dead code now that
3577  * add_missing_from is history, but let's be sure).
3578  */
3579  if (pstate->p_rtable != NIL ||
3580  contain_var_clause(expr))
3581  ereport(ERROR,
3582  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3583  errmsg("cannot use table references in domain check constraint")));
3584 
3585  /*
3586  * Convert to string form for storage.
3587  */
3588  ccbin = nodeToString(expr);
3589 
3590  /*
3591  * Store the constraint in pg_constraint
3592  */
3593  ccoid =
3594  CreateConstraintEntry(constr->conname, /* Constraint Name */
3595  domainNamespace, /* namespace */
3596  CONSTRAINT_CHECK, /* Constraint Type */
3597  false, /* Is Deferrable */
3598  false, /* Is Deferred */
3599  !constr->skip_validation, /* Is Validated */
3600  InvalidOid, /* no parent constraint */
3601  InvalidOid, /* not a relation constraint */
3602  NULL,
3603  0,
3604  0,
3605  domainOid, /* domain constraint */
3606  InvalidOid, /* no associated index */
3607  InvalidOid, /* Foreign key fields */
3608  NULL,
3609  NULL,
3610  NULL,
3611  NULL,
3612  0,
3613  ' ',
3614  ' ',
3615  NULL,
3616  0,
3617  ' ',
3618  NULL, /* not an exclusion constraint */
3619  expr, /* Tree form of check constraint */
3620  ccbin, /* Binary form of check constraint */
3621  true, /* is local */
3622  0, /* inhcount */
3623  false, /* connoinherit */
3624  false, /* conperiod */
3625  false); /* is_internal */
3626  if (constrAddr)
3627  ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
3628 
3629  /*
3630  * Return the compiled constraint expression so the calling routine can
3631  * perform any additional required tests.
3632  */
3633  return ccbin;
3634 }
Node * coerce_to_boolean(ParseState *pstate, Node *node, const char *constructName)
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:121
@ EXPR_KIND_DOMAIN_CHECK
Definition: parse_node.h:69
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, const int16 *fkDeleteSetCols, int numFkDeleteSetCols, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool conPeriod, bool is_internal)
Definition: pg_constraint.c:51
@ CONSTRAINT_DOMAIN
char * conname
Definition: parsenodes.h:2740
void * p_ref_hook_state
Definition: parse_node.h:239
PreParseColumnRefHook p_pre_columnref_hook
Definition: parse_node.h:235
List * p_rtable
Definition: parse_node.h:194
static Node * replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref)
Definition: typecmds.c:3638
bool contain_var_clause(Node *node)
Definition: var.c:403

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

Referenced by AlterDomainAddConstraint(), and DefineDomain().

◆ domainAddNotNullConstraint()

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

Definition at line 3669 of file typecmds.c.

3672 {
3673  Oid ccoid;
3674 
3675  Assert(constr->contype == CONSTR_NOTNULL);
3676 
3677  /*
3678  * Assign or validate constraint name
3679  */
3680  if (constr->conname)
3681  {
3683  domainOid,
3684  constr->conname))
3685  ereport(ERROR,
3687  errmsg("constraint \"%s\" for domain \"%s\" already exists",
3688  constr->conname, domainName)));
3689  }
3690  else
3691  constr->conname = ChooseConstraintName(domainName,
3692  NULL,
3693  "not_null",
3694  domainNamespace,
3695  NIL);
3696 
3697  /*
3698  * Store the constraint in pg_constraint
3699  */
3700  ccoid =
3701  CreateConstraintEntry(constr->conname, /* Constraint Name */
3702  domainNamespace, /* namespace */
3703  CONSTRAINT_NOTNULL, /* Constraint Type */
3704  false, /* Is Deferrable */
3705  false, /* Is Deferred */
3706  !constr->skip_validation, /* Is Validated */
3707  InvalidOid, /* no parent constraint */
3708  InvalidOid, /* not a relation constraint */
3709  NULL,
3710  0,
3711  0,
3712  domainOid, /* domain constraint */
3713  InvalidOid, /* no associated index */
3714  InvalidOid, /* Foreign key fields */
3715  NULL,
3716  NULL,
3717  NULL,
3718  NULL,
3719  0,
3720  ' ',
3721  ' ',
3722  NULL,
3723  0,
3724  ' ',
3725  NULL, /* not an exclusion constraint */
3726  NULL,
3727  NULL,
3728  true, /* is local */
3729  0, /* inhcount */
3730  false, /* connoinherit */
3731  false, /* conperiod */
3732  false); /* is_internal */
3733 
3734  if (constrAddr)
3735  ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
3736 }

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

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

◆ findRangeCanonicalFunction()

static Oid findRangeCanonicalFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2321 of file typecmds.c.

2322 {
2323  Oid argList[1];
2324  Oid procOid;
2325  AclResult aclresult;
2326 
2327  /*
2328  * Range canonical functions must take and return the range type, and must
2329  * be immutable.
2330  */
2331  argList[0] = typeOid;
2332 
2333  procOid = LookupFuncName(procname, 1, argList, true);
2334 
2335  if (!OidIsValid(procOid))
2336  ereport(ERROR,
2337  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2338  errmsg("function %s does not exist",
2339  func_signature_string(procname, 1, NIL, argList))));
2340 
2341  if (get_func_rettype(procOid) != typeOid)
2342  ereport(ERROR,
2343  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2344  errmsg("range canonical function %s must return range type",
2345  func_signature_string(procname, 1, NIL, argList))));
2346 
2347  if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2348  ereport(ERROR,
2349  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2350  errmsg("range canonical function %s must be immutable",
2351  func_signature_string(procname, 1, NIL, argList))));
2352 
2353  /* Also, range type's creator must have permission to call function */
2354  aclresult = object_aclcheck(ProcedureRelationId, procOid, GetUserId(), ACL_EXECUTE);
2355  if (aclresult != ACLCHECK_OK)
2356  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
2357 
2358  return procOid;
2359 }
char func_volatile(Oid funcid)
Definition: lsyscache.c:1780
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1608
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1655
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2029
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2143
#define ACL_EXECUTE
Definition: parsenodes.h:83

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

Referenced by DefineRange().

◆ findRangeSubOpclass()

static Oid findRangeSubOpclass ( List opcname,
Oid  subtype 
)
static

Definition at line 2282 of file typecmds.c.

2283 {
2284  Oid opcid;
2285  Oid opInputType;
2286 
2287  if (opcname != NIL)
2288  {
2289  opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
2290 
2291  /*
2292  * Verify that the operator class accepts this datatype. Note we will
2293  * accept binary compatibility.
2294  */
2295  opInputType = get_opclass_input_type(opcid);
2296  if (!IsBinaryCoercible(subtype, opInputType))
2297  ereport(ERROR,
2298  (errcode(ERRCODE_DATATYPE_MISMATCH),
2299  errmsg("operator class \"%s\" does not accept data type %s",
2300  NameListToString(opcname),
2301  format_type_be(subtype))));
2302  }
2303  else
2304  {
2305  opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
2306  if (!OidIsValid(opcid))
2307  {
2308  /* We spell the error message identically to ResolveOpClass */
2309  ereport(ERROR,
2310  (errcode(ERRCODE_UNDEFINED_OBJECT),
2311  errmsg("data type %s has no default operator class for access method \"%s\"",
2312  format_type_be(subtype), "btree"),
2313  errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
2314  }
2315  }
2316 
2317  return opcid;
2318 }
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2338
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1212
Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
Definition: opclasscmds.c:219
bool IsBinaryCoercible(Oid srctype, Oid targettype)

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

Referenced by DefineRange().

◆ findRangeSubtypeDiffFunction()

static Oid findRangeSubtypeDiffFunction ( List procname,
Oid  subtype 
)
static

Definition at line 2362 of file typecmds.c.

2363 {
2364  Oid argList[2];
2365  Oid procOid;
2366  AclResult aclresult;
2367 
2368  /*
2369  * Range subtype diff functions must take two arguments of the subtype,
2370  * must return float8, and must be immutable.
2371  */
2372  argList[0] = subtype;
2373  argList[1] = subtype;
2374 
2375  procOid = LookupFuncName(procname, 2, argList, true);
2376 
2377  if (!OidIsValid(procOid))
2378  ereport(ERROR,
2379  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2380  errmsg("function %s does not exist",
2381  func_signature_string(procname, 2, NIL, argList))));
2382 
2383  if (get_func_rettype(procOid) != FLOAT8OID)
2384  ereport(ERROR,
2385  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2386  errmsg("range subtype diff function %s must return type %s",
2387  func_signature_string(procname, 2, NIL, argList),
2388  "double precision")));
2389 
2390  if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2391  ereport(ERROR,
2392  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2393  errmsg("range subtype diff function %s must be immutable",
2394  func_signature_string(procname, 2, NIL, argList))));
2395 
2396  /* Also, range type's creator must have permission to call function */
2397  aclresult = object_aclcheck(ProcedureRelationId, procOid, GetUserId(), ACL_EXECUTE);
2398  if (aclresult != ACLCHECK_OK)
2399  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
2400 
2401  return procOid;
2402 }

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

Referenced by DefineRange().

◆ findTypeAnalyzeFunction()

static Oid findTypeAnalyzeFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2208 of file typecmds.c.

2209 {
2210  Oid argList[1];
2211  Oid procOid;
2212 
2213  /*
2214  * Analyze functions always take one INTERNAL argument and return bool.
2215  */
2216  argList[0] = INTERNALOID;
2217 
2218  procOid = LookupFuncName(procname, 1, argList, true);
2219  if (!OidIsValid(procOid))
2220  ereport(ERROR,
2221  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2222  errmsg("function %s does not exist",
2223  func_signature_string(procname, 1, NIL, argList))));
2224 
2225  if (get_func_rettype(procOid) != BOOLOID)
2226  ereport(ERROR,
2227  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2228  errmsg("type analyze function %s must return type %s",
2229  NameListToString(procname), "boolean")));
2230 
2231  return procOid;
2232 }

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

Referenced by AlterType(), and DefineType().

◆ findTypeInputFunction()

static Oid findTypeInputFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 1953 of file typecmds.c.

1954 {
1955  Oid argList[3];
1956  Oid procOid;
1957  Oid procOid2;
1958 
1959  /*
1960  * Input functions can take a single argument of type CSTRING, or three
1961  * arguments (string, typioparam OID, typmod). Whine about ambiguity if
1962  * both forms exist.
1963  */
1964  argList[0] = CSTRINGOID;
1965  argList[1] = OIDOID;
1966  argList[2] = INT4OID;
1967 
1968  procOid = LookupFuncName(procname, 1, argList, true);
1969  procOid2 = LookupFuncName(procname, 3, argList, true);
1970  if (OidIsValid(procOid))
1971  {
1972  if (OidIsValid(procOid2))
1973  ereport(ERROR,
1974  (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
1975  errmsg("type input function %s has multiple matches",
1976  NameListToString(procname))));
1977  }
1978  else
1979  {
1980  procOid = procOid2;
1981  /* If not found, reference the 1-argument signature in error msg */
1982  if (!OidIsValid(procOid))
1983  ereport(ERROR,
1984  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1985  errmsg("function %s does not exist",
1986  func_signature_string(procname, 1, NIL, argList))));
1987  }
1988 
1989  /* Input functions must return the target type. */
1990  if (get_func_rettype(procOid) != typeOid)
1991  ereport(ERROR,
1992  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1993  errmsg("type input function %s must return type %s",
1994  NameListToString(procname), format_type_be(typeOid))));
1995 
1996  /*
1997  * Print warnings if any of the type's I/O functions are marked volatile.
1998  * There is a general assumption that I/O functions are stable or
1999  * immutable; this allows us for example to mark record_in/record_out
2000  * stable rather than volatile. Ideally we would throw errors not just
2001  * warnings here; but since this check is new as of 9.5, and since the
2002  * volatility marking might be just an error-of-omission and not a true
2003  * indication of how the function behaves, we'll let it pass as a warning
2004  * for now.
2005  */
2006  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2007  ereport(WARNING,
2008  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2009  errmsg("type input function %s should not be volatile",
2010  NameListToString(procname))));
2011 
2012  return procOid;
2013 }

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

Referenced by DefineType().

◆ findTypeOutputFunction()

static Oid findTypeOutputFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2016 of file typecmds.c.

2017 {
2018  Oid argList[1];
2019  Oid procOid;
2020 
2021  /*
2022  * Output functions always take a single argument of the type and return
2023  * cstring.
2024  */
2025  argList[0] = typeOid;
2026 
2027  procOid = LookupFuncName(procname, 1, argList, true);
2028  if (!OidIsValid(procOid))
2029  ereport(ERROR,
2030  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2031  errmsg("function %s does not exist",
2032  func_signature_string(procname, 1, NIL, argList))));
2033 
2034  if (get_func_rettype(procOid) != CSTRINGOID)
2035  ereport(ERROR,
2036  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2037  errmsg("type output function %s must return type %s",
2038  NameListToString(procname), "cstring")));
2039 
2040  /* Just a warning for now, per comments in findTypeInputFunction */
2041  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2042  ereport(WARNING,
2043  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2044  errmsg("type output function %s should not be volatile",
2045  NameListToString(procname))));
2046 
2047  return procOid;
2048 }

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

Referenced by DefineType().

◆ findTypeReceiveFunction()

static Oid findTypeReceiveFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2051 of file typecmds.c.

2052 {
2053  Oid argList[3];
2054  Oid procOid;
2055  Oid procOid2;
2056 
2057  /*
2058  * Receive functions can take a single argument of type INTERNAL, or three
2059  * arguments (internal, typioparam OID, typmod). Whine about ambiguity if
2060  * both forms exist.
2061  */
2062  argList[0] = INTERNALOID;
2063  argList[1] = OIDOID;
2064  argList[2] = INT4OID;
2065 
2066  procOid = LookupFuncName(procname, 1, argList, true);
2067  procOid2 = LookupFuncName(procname, 3, argList, true);
2068  if (OidIsValid(procOid))
2069  {
2070  if (OidIsValid(procOid2))
2071  ereport(ERROR,
2072  (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
2073  errmsg("type receive function %s has multiple matches",
2074  NameListToString(procname))));
2075  }
2076  else
2077  {
2078  procOid = procOid2;
2079  /* If not found, reference the 1-argument signature in error msg */
2080  if (!OidIsValid(procOid))
2081  ereport(ERROR,
2082  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2083  errmsg("function %s does not exist",
2084  func_signature_string(procname, 1, NIL, argList))));
2085  }
2086 
2087  /* Receive functions must return the target type. */
2088  if (get_func_rettype(procOid) != typeOid)
2089  ereport(ERROR,
2090  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2091  errmsg("type receive function %s must return type %s",
2092  NameListToString(procname), format_type_be(typeOid))));
2093 
2094  /* Just a warning for now, per comments in findTypeInputFunction */
2095  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2096  ereport(WARNING,
2097  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2098  errmsg("type receive function %s should not be volatile",
2099  NameListToString(procname))));
2100 
2101  return procOid;
2102 }

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

Referenced by AlterType(), and DefineType().

◆ findTypeSendFunction()

static Oid findTypeSendFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2105 of file typecmds.c.

2106 {
2107  Oid argList[1];
2108  Oid procOid;
2109 
2110  /*
2111  * Send functions always take a single argument of the type and return
2112  * bytea.
2113  */
2114  argList[0] = typeOid;
2115 
2116  procOid = LookupFuncName(procname, 1, argList, true);
2117  if (!OidIsValid(procOid))
2118  ereport(ERROR,
2119  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2120  errmsg("function %s does not exist",
2121  func_signature_string(procname, 1, NIL, argList))));
2122 
2123  if (get_func_rettype(procOid) != BYTEAOID)
2124  ereport(ERROR,
2125  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2126  errmsg("type send function %s must return type %s",
2127  NameListToString(procname), "bytea")));
2128 
2129  /* Just a warning for now, per comments in findTypeInputFunction */
2130  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2131  ereport(WARNING,
2132  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2133  errmsg("type send function %s should not be volatile",
2134  NameListToString(procname))));
2135 
2136  return procOid;
2137 }

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

Referenced by AlterType(), and DefineType().

◆ findTypeSubscriptingFunction()

static Oid findTypeSubscriptingFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2235 of file typecmds.c.

2236 {
2237  Oid argList[1];
2238  Oid procOid;
2239 
2240  /*
2241  * Subscripting support functions always take one INTERNAL argument and
2242  * return INTERNAL. (The argument is not used, but we must have it to
2243  * maintain type safety.)
2244  */
2245  argList[0] = INTERNALOID;
2246 
2247  procOid = LookupFuncName(procname, 1, argList, true);
2248  if (!OidIsValid(procOid))
2249  ereport(ERROR,
2250  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2251  errmsg("function %s does not exist",
2252  func_signature_string(procname, 1, NIL, argList))));
2253 
2254  if (get_func_rettype(procOid) != INTERNALOID)
2255  ereport(ERROR,
2256  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2257  errmsg("type subscripting function %s must return type %s",
2258  NameListToString(procname), "internal")));
2259 
2260  /*
2261  * We disallow array_subscript_handler() from being selected explicitly,
2262  * since that must only be applied to autogenerated array types.
2263  */
2264  if (procOid == F_ARRAY_SUBSCRIPT_HANDLER)
2265  ereport(ERROR,
2266  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2267  errmsg("user-defined types cannot use subscripting function %s",
2268  NameListToString(procname))));
2269 
2270  return procOid;
2271 }

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

Referenced by AlterType(), and DefineType().

◆ findTypeTypmodinFunction()

static Oid findTypeTypmodinFunction ( List procname)
static

Definition at line 2140 of file typecmds.c.

2141 {
2142  Oid argList[1];
2143  Oid procOid;
2144 
2145  /*
2146  * typmodin functions always take one cstring[] argument and return int4.
2147  */
2148  argList[0] = CSTRINGARRAYOID;
2149 
2150  procOid = LookupFuncName(procname, 1, argList, true);
2151  if (!OidIsValid(procOid))
2152  ereport(ERROR,
2153  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2154  errmsg("function %s does not exist",
2155  func_signature_string(procname, 1, NIL, argList))));
2156 
2157  if (get_func_rettype(procOid) != INT4OID)
2158  ereport(ERROR,
2159  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2160  errmsg("typmod_in function %s must return type %s",
2161  NameListToString(procname), "integer")));
2162 
2163  /* Just a warning for now, per comments in findTypeInputFunction */
2164  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2165  ereport(WARNING,
2166  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2167  errmsg("type modifier input function %s should not be volatile",
2168  NameListToString(procname))));
2169 
2170  return procOid;
2171 }

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

Referenced by AlterType(), and DefineType().

◆ findTypeTypmodoutFunction()

static Oid findTypeTypmodoutFunction ( List procname)
static

Definition at line 2174 of file typecmds.c.

2175 {
2176  Oid argList[1];
2177  Oid procOid;
2178 
2179  /*
2180  * typmodout functions always take one int4 argument and return cstring.
2181  */
2182  argList[0] = INT4OID;
2183 
2184  procOid = LookupFuncName(procname, 1, argList, true);
2185  if (!OidIsValid(procOid))
2186  ereport(ERROR,
2187  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2188  errmsg("function %s does not exist",
2189  func_signature_string(procname, 1, NIL, argList))));
2190 
2191  if (get_func_rettype(procOid) != CSTRINGOID)
2192  ereport(ERROR,
2193  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2194  errmsg("typmod_out function %s must return type %s",
2195  NameListToString(procname), "cstring")));
2196 
2197  /* Just a warning for now, per comments in findTypeInputFunction */
2198  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
2199  ereport(WARNING,
2200  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2201  errmsg("type modifier output function %s should not be volatile",
2202  NameListToString(procname))));
2203 
2204  return procOid;
2205 }

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

Referenced by AlterType(), and DefineType().

◆ get_rels_with_domain()

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

Definition at line 3321 of file typecmds.c.

3322 {
3323  List *result = NIL;
3324  char *domainTypeName = format_type_be(domainOid);
3325  Relation depRel;
3326  ScanKeyData key[2];
3327  SysScanDesc depScan;
3328  HeapTuple depTup;
3329 
3330  Assert(lockmode != NoLock);
3331 
3332  /* since this function recurses, it could be driven to stack overflow */
3334 
3335  /*
3336  * We scan pg_depend to find those things that depend on the domain. (We
3337  * assume we can ignore refobjsubid for a domain.)
3338  */
3339  depRel = table_open(DependRelationId, AccessShareLock);
3340 
3341  ScanKeyInit(&key[0],
3342  Anum_pg_depend_refclassid,
3343  BTEqualStrategyNumber, F_OIDEQ,
3344  ObjectIdGetDatum(TypeRelationId));
3345  ScanKeyInit(&key[1],
3346  Anum_pg_depend_refobjid,
3347  BTEqualStrategyNumber, F_OIDEQ,
3348  ObjectIdGetDatum(domainOid));
3349 
3350  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
3351  NULL, 2, key);
3352 
3353  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
3354  {
3355  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
3356  RelToCheck *rtc = NULL;
3357  ListCell *rellist;
3358  Form_pg_attribute pg_att;
3359  int ptr;
3360 
3361  /* Check for directly dependent types */
3362  if (pg_depend->classid == TypeRelationId)
3363  {
3364  if (get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN)
3365  {
3366  /*
3367  * This is a sub-domain, so recursively add dependent columns
3368  * to the output list. This is a bit inefficient since we may
3369  * fail to combine RelToCheck entries when attributes of the
3370  * same rel have different derived domain types, but it's
3371  * probably not worth improving.
3372  */
3373  result = list_concat(result,
3374  get_rels_with_domain(pg_depend->objid,
3375  lockmode));
3376  }
3377  else
3378  {
3379  /*
3380  * Otherwise, it is some container type using the domain, so
3381  * fail if there are any columns of this type.
3382  */
3383  find_composite_type_dependencies(pg_depend->objid,
3384  NULL,
3385  domainTypeName);
3386  }
3387  continue;
3388  }
3389 
3390  /* Else, ignore dependees that aren't user columns of relations */
3391  /* (we assume system columns are never of domain types) */
3392  if (pg_depend->classid != RelationRelationId ||
3393  pg_depend->objsubid <= 0)
3394  continue;
3395 
3396  /* See if we already have an entry for this relation */
3397  foreach(rellist, result)
3398  {
3399  RelToCheck *rt = (RelToCheck *) lfirst(rellist);
3400 
3401  if (RelationGetRelid(rt->rel) == pg_depend->objid)
3402  {
3403  rtc = rt;
3404  break;
3405  }
3406  }
3407 
3408  if (rtc == NULL)
3409  {
3410  /* First attribute found for this relation */
3411  Relation rel;
3412 
3413  /* Acquire requested lock on relation */
3414  rel = relation_open(pg_depend->objid, lockmode);
3415 
3416  /*
3417  * Check to see if rowtype is stored anyplace as a composite-type
3418  * column; if so we have to fail, for now anyway.
3419  */
3420  if (OidIsValid(rel->rd_rel->reltype))
3422  NULL,
3423  domainTypeName);
3424 
3425  /*
3426  * Otherwise, we can ignore relations except those with both
3427  * storage and user-chosen column types.
3428  *
3429  * XXX If an index-only scan could satisfy "col::some_domain" from
3430  * a suitable expression index, this should also check expression
3431  * index columns.
3432  */
3433  if (rel->rd_rel->relkind != RELKIND_RELATION &&
3434  rel->rd_rel->relkind != RELKIND_MATVIEW)
3435  {
3436  relation_close(rel, lockmode);
3437  continue;
3438  }
3439 
3440  /* Build the RelToCheck entry with enough space for all atts */
3441  rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
3442  rtc->rel = rel;
3443  rtc->natts = 0;
3444  rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
3445  result = lappend(result, rtc);
3446  }
3447 
3448  /*
3449  * Confirm column has not been dropped, and is of the expected type.
3450  * This defends against an ALTER DROP COLUMN occurring just before we
3451  * acquired lock ... but if the whole table were dropped, we'd still
3452  * have a problem.
3453  */
3454  if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
3455  continue;
3456  pg_att = TupleDescAttr(rtc->rel->rd_att, pg_depend->objsubid - 1);
3457  if (pg_att->attisdropped || pg_att->atttypid != domainOid)
3458  continue;
3459 
3460  /*
3461  * Okay, add column to result. We store the columns in column-number
3462  * order; this is just a hack to improve predictability of regression
3463  * test output ...
3464  */
3466 
3467  ptr = rtc->natts++;
3468  while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
3469  {
3470  rtc->atts[ptr] = rtc->atts[ptr - 1];
3471  ptr--;
3472  }
3473  rtc->atts[ptr] = pg_depend->objsubid;
3474  }
3475 
3476  systable_endscan(depScan);
3477 
3479 
3480  return result;
3481 }
List * lappend(List *list, void *datum)
Definition: list.c:339
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
void * palloc(Size size)
Definition: mcxt.c:1316
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:511
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
int * atts
Definition: typecmds.c:83
Relation rel
Definition: typecmds.c:81
int natts
Definition: typecmds.c:82
TupleDesc rd_att
Definition: rel.h:112
Form_pg_class rd_rel
Definition: rel.h:111
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:6807
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
static List * get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
Definition: typecmds.c:3321

References AccessShareLock, Assert, RelToCheck::atts, BTEqualStrategyNumber, check_stack_depth(), find_composite_type_dependencies(), format_type_be(), get_typtype(), GETSTRUCT, HeapTupleIsValid, sort-test::key, lappend(), lfirst, list_concat(), RelToCheck::natts, NIL, NoLock, ObjectIdGetDatum(), OidIsValid, palloc(), RelationData::rd_att, RelationData::rd_rel, RelToCheck::rel, relation_close(), relation_open(), RelationGetNumberOfAttributes, RelationGetRelid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_open(), and TupleDescAttr.

Referenced by validateDomainCheckConstraint(), and validateDomainNotNullConstraint().

◆ makeMultirangeConstructors()

static void makeMultirangeConstructors ( const char *  name,
Oid  namespace,
Oid  multirangeOid,
Oid  rangeOid,
Oid  rangeArrayOid,
Oid castFuncOid 
)
static

Definition at line 1811 of file typecmds.c.

1814 {
1815  ObjectAddress myself,
1816  referenced;
1817  oidvector *argtypes;
1818  Datum allParamTypes;
1819  ArrayType *allParameterTypes;
1820  Datum paramModes;
1821  ArrayType *parameterModes;
1822 
1823  referenced.classId = TypeRelationId;
1824  referenced.objectId = multirangeOid;
1825  referenced.objectSubId = 0;
1826 
1827  /* 0-arg constructor - for empty multiranges */
1828  argtypes = buildoidvector(NULL, 0);
1829  myself = ProcedureCreate(name, /* name: same as multirange type */
1830  namespace,
1831  false, /* replace */
1832  false, /* returns set */
1833  multirangeOid, /* return type */
1834  BOOTSTRAP_SUPERUSERID, /* proowner */
1835  INTERNALlanguageId, /* language */
1836  F_FMGR_INTERNAL_VALIDATOR,
1837  "multirange_constructor0", /* prosrc */
1838  NULL, /* probin */
1839  NULL, /* prosqlbody */
1840  PROKIND_FUNCTION,
1841  false, /* security_definer */
1842  false, /* leakproof */
1843  true, /* isStrict */
1844  PROVOLATILE_IMMUTABLE, /* volatility */
1845  PROPARALLEL_SAFE, /* parallel safety */
1846  argtypes, /* parameterTypes */
1847  PointerGetDatum(NULL), /* allParameterTypes */
1848  PointerGetDatum(NULL), /* parameterModes */
1849  PointerGetDatum(NULL), /* parameterNames */
1850  NIL, /* parameterDefaults */
1851  PointerGetDatum(NULL), /* trftypes */
1852  PointerGetDatum(NULL), /* proconfig */
1853  InvalidOid, /* prosupport */
1854  1.0, /* procost */
1855  0.0); /* prorows */
1856 
1857  /*
1858  * Make the constructor internally-dependent on the multirange type so
1859  * that they go away silently when the type is dropped. Note that pg_dump
1860  * depends on this choice to avoid dumping the constructors.
1861  */
1862  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1863  pfree(argtypes);
1864 
1865  /*
1866  * 1-arg constructor - for casts
1867  *
1868  * In theory we shouldn't need both this and the vararg (n-arg)
1869  * constructor, but having a separate 1-arg function lets us define casts
1870  * against it.
1871  */
1872  argtypes = buildoidvector(&rangeOid, 1);
1873  myself = ProcedureCreate(name, /* name: same as multirange type */
1874  namespace,
1875  false, /* replace */
1876  false, /* returns set */
1877  multirangeOid, /* return type */
1878  BOOTSTRAP_SUPERUSERID, /* proowner */
1879  INTERNALlanguageId, /* language */
1880  F_FMGR_INTERNAL_VALIDATOR,
1881  "multirange_constructor1", /* prosrc */
1882  NULL, /* probin */
1883  NULL, /* prosqlbody */
1884  PROKIND_FUNCTION,
1885  false, /* security_definer */
1886  false, /* leakproof */
1887  true, /* isStrict */
1888  PROVOLATILE_IMMUTABLE, /* volatility */
1889  PROPARALLEL_SAFE, /* parallel safety */
1890  argtypes, /* parameterTypes */
1891  PointerGetDatum(NULL), /* allParameterTypes */
1892  PointerGetDatum(NULL), /* parameterModes */
1893  PointerGetDatum(NULL), /* parameterNames */
1894  NIL, /* parameterDefaults */
1895  PointerGetDatum(NULL), /* trftypes */
1896  PointerGetDatum(NULL), /* proconfig */
1897  InvalidOid, /* prosupport */
1898  1.0, /* procost */
1899  0.0); /* prorows */
1900  /* ditto */
1901  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1902  pfree(argtypes);
1903  *castFuncOid = myself.objectId;
1904 
1905  /* n-arg constructor - vararg */
1906  argtypes = buildoidvector(&rangeArrayOid, 1);
1907  allParamTypes = ObjectIdGetDatum(rangeArrayOid);
1908  allParameterTypes = construct_array_builtin(&allParamTypes, 1, OIDOID);
1909  paramModes = CharGetDatum(FUNC_PARAM_VARIADIC);
1910  parameterModes = construct_array_builtin(&paramModes, 1, CHAROID);
1911  myself = ProcedureCreate(name, /* name: same as multirange type */
1912  namespace,
1913  false, /* replace */
1914  false, /* returns set */
1915  multirangeOid, /* return type */
1916  BOOTSTRAP_SUPERUSERID, /* proowner */
1917  INTERNALlanguageId, /* language */
1918  F_FMGR_INTERNAL_VALIDATOR,
1919  "multirange_constructor2", /* prosrc */
1920  NULL, /* probin */
1921  NULL, /* prosqlbody */
1922  PROKIND_FUNCTION,
1923  false, /* security_definer */
1924  false, /* leakproof */
1925  true, /* isStrict */
1926  PROVOLATILE_IMMUTABLE, /* volatility */
1927  PROPARALLEL_SAFE, /* parallel safety */
1928  argtypes, /* parameterTypes */
1929  PointerGetDatum(allParameterTypes), /* allParameterTypes */
1930  PointerGetDatum(parameterModes), /* parameterModes */
1931  PointerGetDatum(NULL), /* parameterNames */
1932  NIL, /* parameterDefaults */
1933  PointerGetDatum(NULL), /* trftypes */
1934  PointerGetDatum(NULL), /* proconfig */
1935  InvalidOid, /* prosupport */
1936  1.0, /* procost */
1937  0.0); /* prorows */
1938  /* ditto */
1939  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1940  pfree(argtypes);
1941  pfree(allParameterTypes);
1942  pfree(parameterModes);
1943 }
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3374
oidvector * buildoidvector(const Oid *oids, int n)
Definition: oid.c:87
@ FUNC_PARAM_VARIADIC
Definition: parsenodes.h:3457
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
ObjectAddress ProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, Node *prosqlbody, char prokind, bool security_definer, bool isLeakProof, bool isStrict, char volatility, char parallel, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Datum trftypes, Datum proconfig, Oid prosupport, float4 procost, float4 prorows)
Definition: pg_proc.c:70
Definition: c.h:726
const char * name

References buildoidvector(), CharGetDatum(), ObjectAddress::classId, construct_array_builtin(), DEPENDENCY_INTERNAL, FUNC_PARAM_VARIADIC, InvalidOid, name, NIL, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, pfree(), PointerGetDatum(), ProcedureCreate(), and recordDependencyOn().

Referenced by DefineRange().

◆ makeRangeConstructors()

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

Definition at line 1737 of file typecmds.c.

1739 {
1740  static const char *const prosrc[2] = {"range_constructor2",
1741  "range_constructor3"};
1742  static const int pronargs[2] = {2, 3};
1743 
1744  Oid constructorArgTypes[3];
1745  ObjectAddress myself,
1746  referenced;
1747  int i;
1748 
1749  constructorArgTypes[0] = subtype;
1750  constructorArgTypes[1] = subtype;
1751  constructorArgTypes[2] = TEXTOID;
1752 
1753  referenced.classId = TypeRelationId;
1754  referenced.objectId = rangeOid;
1755  referenced.objectSubId = 0;
1756 
1757  for (i = 0; i < lengthof(prosrc); i++)
1758  {
1759  oidvector *constructorArgTypesVector;
1760 
1761  constructorArgTypesVector = buildoidvector(constructorArgTypes,
1762  pronargs[i]);
1763 
1764  myself = ProcedureCreate(name, /* name: same as range type */
1765  namespace, /* namespace */
1766  false, /* replace */
1767  false, /* returns set */
1768  rangeOid, /* return type */
1769  BOOTSTRAP_SUPERUSERID, /* proowner */
1770  INTERNALlanguageId, /* language */
1771  F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1772  prosrc[i], /* prosrc */
1773  NULL, /* probin */
1774  NULL, /* prosqlbody */
1775  PROKIND_FUNCTION,
1776  false, /* security_definer */
1777  false, /* leakproof */
1778  false, /* isStrict */
1779  PROVOLATILE_IMMUTABLE, /* volatility */
1780  PROPARALLEL_SAFE, /* parallel safety */
1781  constructorArgTypesVector, /* parameterTypes */
1782  PointerGetDatum(NULL), /* allParameterTypes */
1783  PointerGetDatum(NULL), /* parameterModes */
1784  PointerGetDatum(NULL), /* parameterNames */
1785  NIL, /* parameterDefaults */
1786  PointerGetDatum(NULL), /* trftypes */
1787  PointerGetDatum(NULL), /* proconfig */
1788  InvalidOid, /* prosupport */
1789  1.0, /* procost */
1790  0.0); /* prorows */
1791 
1792  /*
1793  * Make the constructors internally-dependent on the range type so
1794  * that they go away silently when the type is dropped. Note that
1795  * pg_dump depends on this choice to avoid dumping the constructors.
1796  */
1797  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1798  }
1799 }
#define lengthof(array)
Definition: c.h:788
int i
Definition: isn.c:73
int16 pronargs
Definition: pg_proc.h:81

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

Referenced by DefineRange().

◆ RemoveTypeById()

void RemoveTypeById ( Oid  typeOid)

Definition at line 657 of file typecmds.c.

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

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

Referenced by doDeletion().

◆ RenameType()

ObjectAddress RenameType ( RenameStmt stmt)

Definition at line 3743 of file typecmds.c.

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

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

Referenced by ExecRenameStmt().

◆ replace_domain_constraint_value()

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

Definition at line 3638 of file typecmds.c.

3639 {
3640  /*
3641  * Check for a reference to "value", and if that's what it is, replace
3642  * with a CoerceToDomainValue as prepared for us by
3643  * domainAddCheckConstraint. (We handle VALUE as a name, not a keyword, to
3644  * avoid breaking a lot of applications that have used VALUE as a column
3645  * name in the past.)
3646  */
3647  if (list_length(cref->fields) == 1)
3648  {
3649  Node *field1 = (Node *) linitial(cref->fields);
3650  char *colname;
3651 
3652  colname = strVal(field1);
3653  if (strcmp(colname, "value") == 0)
3654  {
3655  CoerceToDomainValue *domVal = copyObject(pstate->p_ref_hook_state);
3656 
3657  /* Propagate location knowledge, if any */
3658  domVal->location = cref->location;
3659  return (Node *) domVal;
3660  }
3661  }
3662  return NULL;
3663 }
#define copyObject(obj)
Definition: nodes.h:224
#define linitial(l)
Definition: pg_list.h:178
ParseLoc location
Definition: parsenodes.h:295
List * fields
Definition: parsenodes.h:294
#define strVal(v)
Definition: value.h:82

References copyObject, ColumnRef::fields, linitial, list_length(), ColumnRef::location, CoerceToDomainValue::location, ParseState::p_ref_hook_state, and strVal.

Referenced by domainAddCheckConstraint().

◆ validateDomainCheckConstraint()

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

Definition at line 3201 of file typecmds.c.

3202 {
3203  Expr *expr = (Expr *) stringToNode(ccbin);
3204  List *rels;
3205  ListCell *rt;
3206  EState *estate;
3207  ExprContext *econtext;
3208  ExprState *exprstate;
3209 
3210  /* Need an EState to run ExecEvalExpr */
3211  estate = CreateExecutorState();
3212  econtext = GetPerTupleExprContext(estate);
3213 
3214  /* build execution state for expr */
3215  exprstate = ExecPrepareExpr(expr, estate);
3216 
3217  /* Fetch relation list with attributes based on this domain */
3218  /* ShareLock is sufficient to prevent concurrent data changes */
3219 
3220  rels = get_rels_with_domain(domainoid, ShareLock);
3221 
3222  foreach(rt, rels)
3223  {
3224  RelToCheck *rtc = (RelToCheck *) lfirst(rt);
3225  Relation testrel = rtc->rel;
3226  TupleDesc tupdesc = RelationGetDescr(testrel);
3227  TupleTableSlot *slot;
3228  TableScanDesc scan;
3229  Snapshot snapshot;
3230 
3231  /* Scan all tuples in this relation */
3232  snapshot = RegisterSnapshot(GetLatestSnapshot());
3233  scan = table_beginscan(testrel, snapshot, 0, NULL);
3234  slot = table_slot_create(testrel, NULL);
3235  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3236  {
3237  int i;
3238 
3239  /* Test attributes that are of the domain */
3240  for (i = 0; i < rtc->natts; i++)
3241  {
3242  int attnum = rtc->atts[i];
3243  Datum d;
3244  bool isNull;
3245  Datum conResult;
3246  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
3247 
3248  d = slot_getattr(slot, attnum, &isNull);
3249 
3250  econtext->domainValue_datum = d;
3251  econtext->domainValue_isNull = isNull;
3252 
3253  conResult = ExecEvalExprSwitchContext(exprstate,
3254  econtext,
3255  &isNull);
3256 
3257  if (!isNull && !DatumGetBool(conResult))
3258  {
3259  /*
3260  * In principle the auxiliary information for this error
3261  * should be errdomainconstraint(), but errtablecol()
3262  * seems considerably more useful in practice. Since this
3263  * code only executes in an ALTER DOMAIN command, the
3264  * client should already know which domain is in question,
3265  * and which constraint too.
3266  */
3267  ereport(ERROR,
3268  (errcode(ERRCODE_CHECK_VIOLATION),
3269  errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
3270  NameStr(attr->attname),
3271  RelationGetRelationName(testrel)),
3272  errtablecol(testrel, attnum)));
3273  }
3274  }
3275 
3276  ResetExprContext(econtext);
3277  }
3279  table_endscan(scan);
3280  UnregisterSnapshot(snapshot);
3281 
3282  /* Hold relation lock till commit (XXX bad for concurrency) */
3283  table_close(testrel, NoLock);
3284  }
3285 
3286  FreeExecutorState(estate);
3287 }
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:739
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1341
EState * CreateExecutorState(void)
Definition: execUtils.c:88
void FreeExecutorState(EState *estate)
Definition: execUtils.c:189
#define GetPerTupleExprContext(estate)
Definition: executor.h:550
#define ResetExprContext(econtext)
Definition: executor.h:544
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:348
#define ShareLock
Definition: lockdefs.h:40
int16 attnum
Definition: pg_attribute.h:74
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
void * stringToNode(const char *str)
Definition: read.c:90
#define RelationGetRelationName(relation)
Definition: rel.h:539
int errtablecol(Relation rel, int attnum)
Definition: relcache.c:5962
@ ForwardScanDirection
Definition: sdir.h:28
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:291
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:836
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:794
Datum domainValue_datum
Definition: execnodes.h:286
bool domainValue_isNull
Definition: execnodes.h:288
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:918
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:1029
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:1065
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:395

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

Referenced by AlterDomainAddConstraint(), and AlterDomainValidateConstraint().

◆ validateDomainNotNullConstraint()

static void validateDomainNotNullConstraint ( Oid  domainoid)
static

Definition at line 3136 of file typecmds.c.

3137 {
3138  List *rels;
3139  ListCell *rt;
3140 
3141  /* Fetch relation list with attributes based on this domain */
3142  /* ShareLock is sufficient to prevent concurrent data changes */
3143 
3144  rels = get_rels_with_domain(domainoid, ShareLock);
3145 
3146  foreach(rt, rels)
3147  {
3148  RelToCheck *rtc = (RelToCheck *) lfirst(rt);
3149  Relation testrel = rtc->rel;
3150  TupleDesc tupdesc = RelationGetDescr(testrel);
3151  TupleTableSlot *slot;
3152  TableScanDesc scan;
3153  Snapshot snapshot;
3154 
3155  /* Scan all tuples in this relation */
3156  snapshot = RegisterSnapshot(GetLatestSnapshot());
3157  scan = table_beginscan(testrel, snapshot, 0, NULL);
3158  slot = table_slot_create(testrel, NULL);
3159  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3160  {
3161  int i;
3162 
3163  /* Test attributes that are of the domain */
3164  for (i = 0; i < rtc->natts; i++)
3165  {
3166  int attnum = rtc->atts[i];
3167  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
3168 
3169  if (slot_attisnull(slot, attnum))
3170  {
3171  /*
3172  * In principle the auxiliary information for this error
3173  * should be errdatatype(), but errtablecol() seems
3174  * considerably more useful in practice. Since this code
3175  * only executes in an ALTER DOMAIN command, the client
3176  * should already know which domain is in question.
3177  */
3178  ereport(ERROR,
3179  (errcode(ERRCODE_NOT_NULL_VIOLATION),
3180  errmsg("column \"%s\" of table \"%s\" contains null values",
3181  NameStr(attr->attname),
3182  RelationGetRelationName(testrel)),
3183  errtablecol(testrel, attnum)));
3184  }
3185  }
3186  }
3188  table_endscan(scan);
3189  UnregisterSnapshot(snapshot);
3190 
3191  /* Close each rel after processing, but keep lock */
3192  table_close(testrel, NoLock);
3193  }
3194 }
static bool slot_attisnull(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:381

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

Referenced by AlterDomainAddConstraint(), and AlterDomainNotNull().

Variable Documentation

◆ binary_upgrade_next_array_pg_type_oid

Oid binary_upgrade_next_array_pg_type_oid = InvalidOid

Definition at line 109 of file typecmds.c.

Referenced by AssignTypeArrayOid(), and binary_upgrade_set_next_array_pg_type_oid().

◆ binary_upgrade_next_mrng_array_pg_type_oid

Oid binary_upgrade_next_mrng_array_pg_type_oid = InvalidOid

◆ binary_upgrade_next_mrng_pg_type_oid

Oid binary_upgrade_next_mrng_pg_type_oid = InvalidOid