PostgreSQL Source Code  git master
typecmds.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.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/memutils.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 validateDomainConstraint (Oid domainoid, char *ccbin)
 
static Listget_rels_with_domain (Oid domainOid, LOCKMODE lockmode)
 
static void checkEnumOwner (HeapTuple tup)
 
static char * domainAddConstraint (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 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 2914 of file typecmds.c.

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

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

Referenced by ATExecCmd(), and ProcessUtilitySlow().

◆ AlterDomainDefault()

ObjectAddress AlterDomainDefault ( List names,
Node defaultRaw 
)

Definition at line 2566 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

◆ AlterDomainDropConstraint()

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

Definition at line 2815 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterDomainNotNull()

ObjectAddress AlterDomainNotNull ( List names,
bool  notNull 
)

Definition at line 2695 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterDomainValidateConstraint()

ObjectAddress AlterDomainValidateConstraint ( List names,
const char *  constrName 
)

Definition at line 3030 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterEnum()

ObjectAddress AlterEnum ( AlterEnumStmt stmt)

Definition at line 1261 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterType()

ObjectAddress AlterType ( AlterTypeStmt stmt)

Definition at line 4089 of file typecmds.c.

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

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

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

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

3909 {
3910  Oid elemOid;
3911 
3912  /* check permissions on type */
3913  if (!object_ownercheck(TypeRelationId, typeOid, GetUserId()))
3915 
3916  /* don't allow direct alteration of array types */
3917  elemOid = get_element_type(typeOid);
3918  if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3919  ereport(ERROR,
3920  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3921  errmsg("cannot alter array type %s",
3922  format_type_be(typeOid)),
3923  errhint("You can alter type %s, which will alter the array type as well.",
3924  format_type_be(elemOid))));
3925 
3926  /* and do the work */
3927  return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3928 }
#define OidIsValid(objectId)
Definition: c.h:764
int errhint(const char *fmt,...)
Definition: elog.c:1316
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2741
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2769
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3946

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

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

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

Referenced by AlterTableNamespaceInternal(), and AlterTypeNamespace_oid().

◆ AlterTypeOwner()

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

Definition at line 3668 of file typecmds.c.

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

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_namespace_name(), get_rel_relkind(), GETSTRUCT, GetUserId(), heap_copytuple(), LookupTypeName(), makeTypeNameFromNameList(), object_aclcheck(), OBJECT_DOMAIN, object_ownercheck(), OBJECT_SCHEMA, ObjectAddressSet, 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 3776 of file typecmds.c.

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

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

Referenced by AlterTypeOwner(), and shdepReassignOwned().

◆ AlterTypeOwnerInternal()

void AlterTypeOwnerInternal ( Oid  typeOid,
Oid  newOwnerId 
)

Definition at line 3816 of file typecmds.c.

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

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

Referenced by AlterTypeOwner_oid(), and ATExecChangeOwner().

◆ AlterTypeRecurse()

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

Definition at line 4340 of file typecmds.c.

4343 {
4344  Datum values[Natts_pg_type];
4345  bool nulls[Natts_pg_type];
4346  bool replaces[Natts_pg_type];
4347  HeapTuple newtup;
4348  SysScanDesc scan;
4349  ScanKeyData key[1];
4350  HeapTuple domainTup;
4351 
4352  /* Since this function recurses, it could be driven to stack overflow */
4354 
4355  /* Update the current type's tuple */
4356  memset(values, 0, sizeof(values));
4357  memset(nulls, 0, sizeof(nulls));
4358  memset(replaces, 0, sizeof(replaces));
4359 
4360  if (atparams->updateStorage)
4361  {
4362  replaces[Anum_pg_type_typstorage - 1] = true;
4363  values[Anum_pg_type_typstorage - 1] = CharGetDatum(atparams->storage);
4364  }
4365  if (atparams->updateReceive)
4366  {
4367  replaces[Anum_pg_type_typreceive - 1] = true;
4368  values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(atparams->receiveOid);
4369  }
4370  if (atparams->updateSend)
4371  {
4372  replaces[Anum_pg_type_typsend - 1] = true;
4373  values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(atparams->sendOid);
4374  }
4375  if (atparams->updateTypmodin)
4376  {
4377  replaces[Anum_pg_type_typmodin - 1] = true;
4378  values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(atparams->typmodinOid);
4379  }
4380  if (atparams->updateTypmodout)
4381  {
4382  replaces[Anum_pg_type_typmodout - 1] = true;
4383  values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(atparams->typmodoutOid);
4384  }
4385  if (atparams->updateAnalyze)
4386  {
4387  replaces[Anum_pg_type_typanalyze - 1] = true;
4388  values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(atparams->analyzeOid);
4389  }
4390  if (atparams->updateSubscript)
4391  {
4392  replaces[Anum_pg_type_typsubscript - 1] = true;
4393  values[Anum_pg_type_typsubscript - 1] = ObjectIdGetDatum(atparams->subscriptOid);
4394  }
4395 
4396  newtup = heap_modify_tuple(tup, RelationGetDescr(catalog),
4397  values, nulls, replaces);
4398 
4399  CatalogTupleUpdate(catalog, &newtup->t_self, newtup);
4400 
4401  /* Rebuild dependencies for this type */
4402  GenerateTypeDependencies(newtup,
4403  catalog,
4404  NULL, /* don't have defaultExpr handy */
4405  NULL, /* don't have typacl handy */
4406  0, /* we rejected composite types above */
4407  isImplicitArray, /* it might be an array */
4408  isImplicitArray, /* dependent iff it's array */
4409  false, /* don't touch extension membership */
4410  true);
4411 
4412  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
4413 
4414  /*
4415  * Arrays inherit their base type's typmodin and typmodout, but none of
4416  * the other properties we're concerned with here. Recurse to the array
4417  * type if needed.
4418  */
4419  if (!isImplicitArray &&
4420  (atparams->updateTypmodin || atparams->updateTypmodout))
4421  {
4422  Oid arrtypoid = ((Form_pg_type) GETSTRUCT(newtup))->typarray;
4423 
4424  if (OidIsValid(arrtypoid))
4425  {
4426  HeapTuple arrtup;
4427  AlterTypeRecurseParams arrparams;
4428 
4429  arrtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrtypoid));
4430  if (!HeapTupleIsValid(arrtup))
4431  elog(ERROR, "cache lookup failed for type %u", arrtypoid);
4432 
4433  memset(&arrparams, 0, sizeof(arrparams));
4434  arrparams.updateTypmodin = atparams->updateTypmodin;
4435  arrparams.updateTypmodout = atparams->updateTypmodout;
4436  arrparams.typmodinOid = atparams->typmodinOid;
4437  arrparams.typmodoutOid = atparams->typmodoutOid;
4438 
4439  AlterTypeRecurse(arrtypoid, true, arrtup, catalog, &arrparams);
4440 
4441  ReleaseSysCache(arrtup);
4442  }
4443  }
4444 
4445  /*
4446  * Now we need to recurse to domains. However, some properties are not
4447  * inherited by domains, so clear the update flags for those.
4448  */
4449  atparams->updateReceive = false; /* domains use F_DOMAIN_RECV */
4450  atparams->updateTypmodin = false; /* domains don't have typmods */
4451  atparams->updateTypmodout = false;
4452  atparams->updateSubscript = false; /* domains don't have subscriptors */
4453 
4454  /* Skip the scan if nothing remains to be done */
4455  if (!(atparams->updateStorage ||
4456  atparams->updateSend ||
4457  atparams->updateAnalyze))
4458  return;
4459 
4460  /* Search pg_type for possible domains over this type */
4461  ScanKeyInit(&key[0],
4462  Anum_pg_type_typbasetype,
4463  BTEqualStrategyNumber, F_OIDEQ,
4464  ObjectIdGetDatum(typeOid));
4465 
4466  scan = systable_beginscan(catalog, InvalidOid, false,
4467  NULL, 1, key);
4468 
4469  while ((domainTup = systable_getnext(scan)) != NULL)
4470  {
4471  Form_pg_type domainForm = (Form_pg_type) GETSTRUCT(domainTup);
4472 
4473  /*
4474  * Shouldn't have a nonzero typbasetype in a non-domain, but let's
4475  * check
4476  */
4477  if (domainForm->typtype != TYPTYPE_DOMAIN)
4478  continue;
4479 
4480  AlterTypeRecurse(domainForm->oid, false, domainTup, catalog, atparams);
4481  }
4482 
4483  systable_endscan(scan);
4484 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
void check_stack_depth(void)
Definition: postgres.c:3523
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, TYPEOID, 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 2400 of file typecmds.c.

2401 {
2402  Oid type_array_oid;
2403 
2404  /* Use binary-upgrade override for pg_type.typarray? */
2405  if (IsBinaryUpgrade)
2406  {
2408  ereport(ERROR,
2409  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2410  errmsg("pg_type array OID value not set when in binary upgrade mode")));
2411 
2412  type_array_oid = binary_upgrade_next_array_pg_type_oid;
2414  }
2415  else
2416  {
2417  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2418 
2419  type_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2420  Anum_pg_type_oid);
2421  table_close(pg_type, AccessShareLock);
2422  }
2423 
2424  return type_array_oid;
2425 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:393
bool IsBinaryUpgrade
Definition: globals.c:114
Oid binary_upgrade_next_array_pg_type_oid
Definition: typecmds.c:109

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

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

◆ AssignTypeMultirangeArrayOid()

Oid AssignTypeMultirangeArrayOid ( void  )

Definition at line 2466 of file typecmds.c.

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

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

3416 {
3417  Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
3418 
3419  /* Check that this is actually a domain */
3420  if (typTup->typtype != TYPTYPE_DOMAIN)
3421  ereport(ERROR,
3422  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3423  errmsg("%s is not a domain",
3424  format_type_be(typTup->oid))));
3425 
3426  /* Permission check: must own type */
3427  if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
3429 }

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

1310 {
1311  Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1312 
1313  /* Check that this is actually an enum */
1314  if (typTup->typtype != TYPTYPE_ENUM)
1315  ereport(ERROR,
1316  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1317  errmsg("%s is not an enum",
1318  format_type_be(typTup->oid))));
1319 
1320  /* Permission check: must own type */
1321  if (!object_ownercheck(TypeRelationId, typTup->oid, GetUserId()))
1323 }

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

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

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

Referenced by ProcessUtilitySlow().

◆ DefineDomain()

ObjectAddress DefineDomain ( CreateDomainStmt stmt)

Definition at line 693 of file typecmds.c.

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

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(), domainAddConstraint(), 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(), TYPENAMENSP, TypeNameToString(), typenameType(), and TYPEOID.

Referenced by ProcessUtilitySlow().

◆ DefineEnum()

ObjectAddress DefineEnum ( CreateEnumStmt stmt)

Definition at line 1137 of file typecmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ DefineRange()

ObjectAddress DefineRange ( ParseState pstate,
CreateRangeStmt stmt 
)

Definition at line 1336 of file typecmds.c.

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

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(), TYPENAMENSP, and typenameTypeId().

Referenced by ProcessUtilitySlow().

◆ DefineType()

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

Definition at line 148 of file typecmds.c.

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

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(), TYPENAMENSP, typenameType(), typenameTypeId(), TypeShellMake(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ domainAddConstraint()

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

Definition at line 3435 of file typecmds.c.

3438 {
3439  Node *expr;
3440  char *ccbin;
3441  ParseState *pstate;
3442  CoerceToDomainValue *domVal;
3443  Oid ccoid;
3444 
3445  /*
3446  * Assign or validate constraint name
3447  */
3448  if (constr->conname)
3449  {
3451  domainOid,
3452  constr->conname))
3453  ereport(ERROR,
3455  errmsg("constraint \"%s\" for domain \"%s\" already exists",
3456  constr->conname, domainName)));
3457  }
3458  else
3459  constr->conname = ChooseConstraintName(domainName,
3460  NULL,
3461  "check",
3462  domainNamespace,
3463  NIL);
3464 
3465  /*
3466  * Convert the A_EXPR in raw_expr into an EXPR
3467  */
3468  pstate = make_parsestate(NULL);
3469 
3470  /*
3471  * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
3472  * the expression. Note that it will appear to have the type of the base
3473  * type, not the domain. This seems correct since within the check
3474  * expression, we should not assume the input value can be considered a
3475  * member of the domain.
3476  */
3477  domVal = makeNode(CoerceToDomainValue);
3478  domVal->typeId = baseTypeOid;
3479  domVal->typeMod = typMod;
3480  domVal->collation = get_typcollation(baseTypeOid);
3481  domVal->location = -1; /* will be set when/if used */
3482 
3484  pstate->p_ref_hook_state = (void *) domVal;
3485 
3486  expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
3487 
3488  /*
3489  * Make sure it yields a boolean result.
3490  */
3491  expr = coerce_to_boolean(pstate, expr, "CHECK");
3492 
3493  /*
3494  * Fix up collation information.
3495  */
3496  assign_expr_collations(pstate, expr);
3497 
3498  /*
3499  * Domains don't allow variables (this is probably dead code now that
3500  * add_missing_from is history, but let's be sure).
3501  */
3502  if (pstate->p_rtable != NIL ||
3503  contain_var_clause(expr))
3504  ereport(ERROR,
3505  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3506  errmsg("cannot use table references in domain check constraint")));
3507 
3508  /*
3509  * Convert to string form for storage.
3510  */
3511  ccbin = nodeToString(expr);
3512 
3513  /*
3514  * Store the constraint in pg_constraint
3515  */
3516  ccoid =
3517  CreateConstraintEntry(constr->conname, /* Constraint Name */
3518  domainNamespace, /* namespace */
3519  CONSTRAINT_CHECK, /* Constraint Type */
3520  false, /* Is Deferrable */
3521  false, /* Is Deferred */
3522  !constr->skip_validation, /* Is Validated */
3523  InvalidOid, /* no parent constraint */
3524  InvalidOid, /* not a relation constraint */
3525  NULL,
3526  0,
3527  0,
3528  domainOid, /* domain constraint */
3529  InvalidOid, /* no associated index */
3530  InvalidOid, /* Foreign key fields */
3531  NULL,
3532  NULL,
3533  NULL,
3534  NULL,
3535  0,
3536  ' ',
3537  ' ',
3538  NULL,
3539  0,
3540  ' ',
3541  NULL, /* not an exclusion constraint */
3542  expr, /* Tree form of check constraint */
3543  ccbin, /* Binary form of check constraint */
3544  true, /* is local */
3545  0, /* inhcount */
3546  false, /* connoinherit */
3547  false); /* is_internal */
3548  if (constrAddr)
3549  ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
3550 
3551  /*
3552  * Return the compiled constraint expression so the calling routine can
3553  * perform any additional required tests.
3554  */
3555  return ccbin;
3556 }
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:110
@ EXPR_KIND_DOMAIN_CHECK
Definition: parse_node.h:68
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 is_internal)
Definition: pg_constraint.c:51
@ CONSTRAINT_DOMAIN
char * conname
Definition: parsenodes.h:2598
void * p_ref_hook_state
Definition: parse_node.h:238
PreParseColumnRefHook p_pre_columnref_hook
Definition: parse_node.h:234
List * p_rtable
Definition: parse_node.h:193
static Node * replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref)
Definition: typecmds.c:3560
bool contain_var_clause(Node *node)
Definition: var.c:403

References assign_expr_collations(), ChooseConstraintName(), coerce_to_boolean(), Constraint::conname, CONSTRAINT_DOMAIN, ConstraintNameIsUsed(), contain_var_clause(), 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().

◆ findRangeCanonicalFunction()

static Oid findRangeCanonicalFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2311 of file typecmds.c.

2312 {
2313  Oid argList[1];
2314  Oid procOid;
2315  AclResult aclresult;
2316 
2317  /*
2318  * Range canonical functions must take and return the range type, and must
2319  * be immutable.
2320  */
2321  argList[0] = typeOid;
2322 
2323  procOid = LookupFuncName(procname, 1, argList, true);
2324 
2325  if (!OidIsValid(procOid))
2326  ereport(ERROR,
2327  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2328  errmsg("function %s does not exist",
2329  func_signature_string(procname, 1, NIL, argList))));
2330 
2331  if (get_func_rettype(procOid) != typeOid)
2332  ereport(ERROR,
2333  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2334  errmsg("range canonical function %s must return range type",
2335  func_signature_string(procname, 1, NIL, argList))));
2336 
2337  if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2338  ereport(ERROR,
2339  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2340  errmsg("range canonical function %s must be immutable",
2341  func_signature_string(procname, 1, NIL, argList))));
2342 
2343  /* Also, range type's creator must have permission to call function */
2344  aclresult = object_aclcheck(ProcedureRelationId, procOid, GetUserId(), ACL_EXECUTE);
2345  if (aclresult != ACLCHECK_OK)
2346  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
2347 
2348  return procOid;
2349 }
char func_volatile(Oid funcid)
Definition: lsyscache.c:1784
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1612
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1659
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:90

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

2273 {
2274  Oid opcid;
2275  Oid opInputType;
2276 
2277  if (opcname != NIL)
2278  {
2279  opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
2280 
2281  /*
2282  * Verify that the operator class accepts this datatype. Note we will
2283  * accept binary compatibility.
2284  */
2285  opInputType = get_opclass_input_type(opcid);
2286  if (!IsBinaryCoercible(subtype, opInputType))
2287  ereport(ERROR,
2288  (errcode(ERRCODE_DATATYPE_MISMATCH),
2289  errmsg("operator class \"%s\" does not accept data type %s",
2290  NameListToString(opcname),
2291  format_type_be(subtype))));
2292  }
2293  else
2294  {
2295  opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
2296  if (!OidIsValid(opcid))
2297  {
2298  /* We spell the error message identically to ResolveOpClass */
2299  ereport(ERROR,
2300  (errcode(ERRCODE_UNDEFINED_OBJECT),
2301  errmsg("data type %s has no default operator class for access method \"%s\"",
2302  format_type_be(subtype), "btree"),
2303  errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
2304  }
2305  }
2306 
2307  return opcid;
2308 }
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2310
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1216
Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
Definition: opclasscmds.c:220
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 2352 of file typecmds.c.

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

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

2199 {
2200  Oid argList[1];
2201  Oid procOid;
2202 
2203  /*
2204  * Analyze functions always take one INTERNAL argument and return bool.
2205  */
2206  argList[0] = INTERNALOID;
2207 
2208  procOid = LookupFuncName(procname, 1, argList, true);
2209  if (!OidIsValid(procOid))
2210  ereport(ERROR,
2211  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2212  errmsg("function %s does not exist",
2213  func_signature_string(procname, 1, NIL, argList))));
2214 
2215  if (get_func_rettype(procOid) != BOOLOID)
2216  ereport(ERROR,
2217  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2218  errmsg("type analyze function %s must return type %s",
2219  NameListToString(procname), "boolean")));
2220 
2221  return procOid;
2222 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3247 {
3248  List *result = NIL;
3249  char *domainTypeName = format_type_be(domainOid);
3250  Relation depRel;
3251  ScanKeyData key[2];
3252  SysScanDesc depScan;
3253  HeapTuple depTup;
3254 
3255  Assert(lockmode != NoLock);
3256 
3257  /* since this function recurses, it could be driven to stack overflow */
3259 
3260  /*
3261  * We scan pg_depend to find those things that depend on the domain. (We
3262  * assume we can ignore refobjsubid for a domain.)
3263  */
3264  depRel = table_open(DependRelationId, AccessShareLock);
3265 
3266  ScanKeyInit(&key[0],
3267  Anum_pg_depend_refclassid,
3268  BTEqualStrategyNumber, F_OIDEQ,
3269  ObjectIdGetDatum(TypeRelationId));
3270  ScanKeyInit(&key[1],
3271  Anum_pg_depend_refobjid,
3272  BTEqualStrategyNumber, F_OIDEQ,
3273  ObjectIdGetDatum(domainOid));
3274 
3275  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
3276  NULL, 2, key);
3277 
3278  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
3279  {
3280  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
3281  RelToCheck *rtc = NULL;
3282  ListCell *rellist;
3283  Form_pg_attribute pg_att;
3284  int ptr;
3285 
3286  /* Check for directly dependent types */
3287  if (pg_depend->classid == TypeRelationId)
3288  {
3289  if (get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN)
3290  {
3291  /*
3292  * This is a sub-domain, so recursively add dependent columns
3293  * to the output list. This is a bit inefficient since we may
3294  * fail to combine RelToCheck entries when attributes of the
3295  * same rel have different derived domain types, but it's
3296  * probably not worth improving.
3297  */
3298  result = list_concat(result,
3299  get_rels_with_domain(pg_depend->objid,
3300  lockmode));
3301  }
3302  else
3303  {
3304  /*
3305  * Otherwise, it is some container type using the domain, so
3306  * fail if there are any columns of this type.
3307  */
3308  find_composite_type_dependencies(pg_depend->objid,
3309  NULL,
3310  domainTypeName);
3311  }
3312  continue;
3313  }
3314 
3315  /* Else, ignore dependees that aren't user columns of relations */
3316  /* (we assume system columns are never of domain types) */
3317  if (pg_depend->classid != RelationRelationId ||
3318  pg_depend->objsubid <= 0)
3319  continue;
3320 
3321  /* See if we already have an entry for this relation */
3322  foreach(rellist, result)
3323  {
3324  RelToCheck *rt = (RelToCheck *) lfirst(rellist);
3325 
3326  if (RelationGetRelid(rt->rel) == pg_depend->objid)
3327  {
3328  rtc = rt;
3329  break;
3330  }
3331  }
3332 
3333  if (rtc == NULL)
3334  {
3335  /* First attribute found for this relation */
3336  Relation rel;
3337 
3338  /* Acquire requested lock on relation */
3339  rel = relation_open(pg_depend->objid, lockmode);
3340 
3341  /*
3342  * Check to see if rowtype is stored anyplace as a composite-type
3343  * column; if so we have to fail, for now anyway.
3344  */
3345  if (OidIsValid(rel->rd_rel->reltype))
3347  NULL,
3348  domainTypeName);
3349 
3350  /*
3351  * Otherwise, we can ignore relations except those with both
3352  * storage and user-chosen column types.
3353  *
3354  * XXX If an index-only scan could satisfy "col::some_domain" from
3355  * a suitable expression index, this should also check expression
3356  * index columns.
3357  */
3358  if (rel->rd_rel->relkind != RELKIND_RELATION &&
3359  rel->rd_rel->relkind != RELKIND_MATVIEW)
3360  {
3361  relation_close(rel, lockmode);
3362  continue;
3363  }
3364 
3365  /* Build the RelToCheck entry with enough space for all atts */
3366  rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
3367  rtc->rel = rel;
3368  rtc->natts = 0;
3369  rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
3370  result = lappend(result, rtc);
3371  }
3372 
3373  /*
3374  * Confirm column has not been dropped, and is of the expected type.
3375  * This defends against an ALTER DROP COLUMN occurring just before we
3376  * acquired lock ... but if the whole table were dropped, we'd still
3377  * have a problem.
3378  */
3379  if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
3380  continue;
3381  pg_att = TupleDescAttr(rtc->rel->rd_att, pg_depend->objsubid - 1);
3382  if (pg_att->attisdropped || pg_att->atttypid != domainOid)
3383  continue;
3384 
3385  /*
3386  * Okay, add column to result. We store the columns in column-number
3387  * order; this is just a hack to improve predictability of regression
3388  * test output ...
3389  */
3391 
3392  ptr = rtc->natts++;
3393  while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
3394  {
3395  rtc->atts[ptr] = rtc->atts[ptr - 1];
3396  ptr--;
3397  }
3398  rtc->atts[ptr] = pg_depend->objsubid;
3399  }
3400 
3401  systable_endscan(depScan);
3402 
3404 
3405  return result;
3406 }
List * lappend(List *list, void *datum)
Definition: list.c:338
List * list_concat(List *list1, const List *list2)
Definition: list.c:560
void * palloc(Size size)
Definition: mcxt.c:1226
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
#define RelationGetRelid(relation)
Definition: rel.h:504
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:510
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
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:6587

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 AlterDomainNotNull(), and validateDomainConstraint().

◆ makeMultirangeConstructors()

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

Definition at line 1801 of file typecmds.c.

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

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

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

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

Referenced by doDeletion().

◆ RenameType()

ObjectAddress RenameType ( RenameStmt stmt)

Definition at line 3591 of file typecmds.c.

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

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(), typenameTypeId(), and TYPEOID.

Referenced by ExecRenameStmt().

◆ replace_domain_constraint_value()

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

Definition at line 3560 of file typecmds.c.

3561 {
3562  /*
3563  * Check for a reference to "value", and if that's what it is, replace
3564  * with a CoerceToDomainValue as prepared for us by domainAddConstraint.
3565  * (We handle VALUE as a name, not a keyword, to avoid breaking a lot of
3566  * applications that have used VALUE as a column name in the past.)
3567  */
3568  if (list_length(cref->fields) == 1)
3569  {
3570  Node *field1 = (Node *) linitial(cref->fields);
3571  char *colname;
3572 
3573  colname = strVal(field1);
3574  if (strcmp(colname, "value") == 0)
3575  {
3576  CoerceToDomainValue *domVal = copyObject(pstate->p_ref_hook_state);
3577 
3578  /* Propagate location knowledge, if any */
3579  domVal->location = cref->location;
3580  return (Node *) domVal;
3581  }
3582  }
3583  return NULL;
3584 }
#define copyObject(obj)
Definition: nodes.h:244
#define linitial(l)
Definition: pg_list.h:178
int location
Definition: parsenodes.h:292
List * fields
Definition: parsenodes.h:291
#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 domainAddConstraint().

◆ validateDomainConstraint()

static void validateDomainConstraint ( Oid  domainoid,
char *  ccbin 
)
static

Definition at line 3126 of file typecmds.c.

3127 {
3128  Expr *expr = (Expr *) stringToNode(ccbin);
3129  List *rels;
3130  ListCell *rt;
3131  EState *estate;
3132  ExprContext *econtext;
3133  ExprState *exprstate;
3134 
3135  /* Need an EState to run ExecEvalExpr */
3136  estate = CreateExecutorState();
3137  econtext = GetPerTupleExprContext(estate);
3138 
3139  /* build execution state for expr */
3140  exprstate = ExecPrepareExpr(expr, estate);
3141 
3142  /* Fetch relation list with attributes based on this domain */
3143  /* ShareLock is sufficient to prevent concurrent data changes */
3144 
3145  rels = get_rels_with_domain(domainoid, ShareLock);
3146 
3147  foreach(rt, rels)
3148  {
3149  RelToCheck *rtc = (RelToCheck *) lfirst(rt);
3150  Relation testrel = rtc->rel;
3151  TupleDesc tupdesc = RelationGetDescr(testrel);
3152  TupleTableSlot *slot;
3153  TableScanDesc scan;
3154  Snapshot snapshot;
3155 
3156  /* Scan all tuples in this relation */
3157  snapshot = RegisterSnapshot(GetLatestSnapshot());
3158  scan = table_beginscan(testrel, snapshot, 0, NULL);
3159  slot = table_slot_create(testrel, NULL);
3160  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
3161  {
3162  int i;
3163 
3164  /* Test attributes that are of the domain */
3165  for (i = 0; i < rtc->natts; i++)
3166  {
3167  int attnum = rtc->atts[i];
3168  Datum d;
3169  bool isNull;
3170  Datum conResult;
3171  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
3172 
3173  d = slot_getattr(slot, attnum, &isNull);
3174 
3175  econtext->domainValue_datum = d;
3176  econtext->domainValue_isNull = isNull;
3177 
3178  conResult = ExecEvalExprSwitchContext(exprstate,
3179  econtext,
3180  &isNull);
3181 
3182  if (!isNull && !DatumGetBool(conResult))
3183  {
3184  /*
3185  * In principle the auxiliary information for this error
3186  * should be errdomainconstraint(), but errtablecol()
3187  * seems considerably more useful in practice. Since this
3188  * code only executes in an ALTER DOMAIN command, the
3189  * client should already know which domain is in question,
3190  * and which constraint too.
3191  */
3192  ereport(ERROR,
3193  (errcode(ERRCODE_CHECK_VIOLATION),
3194  errmsg("column \"%s\" of table \"%s\" contains values that violate the new constraint",
3195  NameStr(attr->attname),
3196  RelationGetRelationName(testrel)),
3197  errtablecol(testrel, attnum)));
3198  }
3199  }
3200 
3201  ResetExprContext(econtext);
3202  }
3204  table_endscan(scan);
3205  UnregisterSnapshot(snapshot);
3206 
3207  /* Hold relation lock till commit (XXX bad for concurrency) */
3208  table_close(testrel, NoLock);
3209  }
3210 
3211  FreeExecutorState(estate);
3212 }
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:736
EState * CreateExecutorState(void)
Definition: execUtils.c:93
void FreeExecutorState(EState *estate)
Definition: execUtils.c:194
#define GetPerTupleExprContext(estate)
Definition: executor.h:549
#define ResetExprContext(econtext)
Definition: executor.h:543
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:347
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
void * stringToNode(const char *str)
Definition: read.c:90
Datum domainValue_datum
Definition: execnodes.h:280
bool domainValue_isNull
Definition: execnodes.h:282
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:388

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