PostgreSQL Source Code  git master
typecmds.c File Reference
#include "postgres.h"
#include "access/htup_details.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_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/var.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/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
 

Functions

static void makeRangeConstructors (const char *name, Oid namespace, Oid rangeOid, Oid subtype)
 
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 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)
 
ObjectAddress DefineType (ParseState *pstate, List *names, List *parameters)
 
void RemoveTypeById (Oid typeOid)
 
ObjectAddress DefineDomain (CreateDomainStmt *stmt)
 
ObjectAddress DefineEnum (CreateEnumStmt *stmt)
 
ObjectAddress AlterEnum (AlterEnumStmt *stmt, bool isTopLevel)
 
ObjectAddress DefineRange (CreateRangeStmt *stmt)
 
Oid AssignTypeArrayOid (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)
 

Variables

Oid binary_upgrade_next_array_pg_type_oid = InvalidOid
 

Function Documentation

◆ AlterDomainAddConstraint()

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

Definition at line 2539 of file typecmds.c.

References 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, heap_close, heap_open(), HeapTupleIsValid, IsA, makeTypeNameFromNameList(), NameStr, nodeTag, ObjectAddressSet, ObjectIdGetDatum, RowExclusiveLock, SearchSysCacheCopy1, Constraint::skip_validation, typenameTypeId(), TYPEOID, and validateDomainConstraint().

Referenced by ATExecCmd(), and ProcessUtilitySlow().

2541 {
2542  TypeName *typename;
2543  Oid domainoid;
2544  Relation typrel;
2545  HeapTuple tup;
2546  Form_pg_type typTup;
2547  Constraint *constr;
2548  char *ccbin;
2549  ObjectAddress address;
2550 
2551  /* Make a TypeName so we can use standard type lookup machinery */
2552  typename = makeTypeNameFromNameList(names);
2553  domainoid = typenameTypeId(NULL, typename);
2554 
2555  /* Look up the domain in the type table */
2556  typrel = heap_open(TypeRelationId, RowExclusiveLock);
2557 
2558  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2559  if (!HeapTupleIsValid(tup))
2560  elog(ERROR, "cache lookup failed for type %u", domainoid);
2561  typTup = (Form_pg_type) GETSTRUCT(tup);
2562 
2563  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2564  checkDomainOwner(tup);
2565 
2566  if (!IsA(newConstraint, Constraint))
2567  elog(ERROR, "unrecognized node type: %d",
2568  (int) nodeTag(newConstraint));
2569 
2570  constr = (Constraint *) newConstraint;
2571 
2572  switch (constr->contype)
2573  {
2574  case CONSTR_CHECK:
2575  /* processed below */
2576  break;
2577 
2578  case CONSTR_UNIQUE:
2579  ereport(ERROR,
2580  (errcode(ERRCODE_SYNTAX_ERROR),
2581  errmsg("unique constraints not possible for domains")));
2582  break;
2583 
2584  case CONSTR_PRIMARY:
2585  ereport(ERROR,
2586  (errcode(ERRCODE_SYNTAX_ERROR),
2587  errmsg("primary key constraints not possible for domains")));
2588  break;
2589 
2590  case CONSTR_EXCLUSION:
2591  ereport(ERROR,
2592  (errcode(ERRCODE_SYNTAX_ERROR),
2593  errmsg("exclusion constraints not possible for domains")));
2594  break;
2595 
2596  case CONSTR_FOREIGN:
2597  ereport(ERROR,
2598  (errcode(ERRCODE_SYNTAX_ERROR),
2599  errmsg("foreign key constraints not possible for domains")));
2600  break;
2601 
2604  case CONSTR_ATTR_DEFERRED:
2605  case CONSTR_ATTR_IMMEDIATE:
2606  ereport(ERROR,
2607  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2608  errmsg("specifying constraint deferrability not supported for domains")));
2609  break;
2610 
2611  default:
2612  elog(ERROR, "unrecognized constraint subtype: %d",
2613  (int) constr->contype);
2614  break;
2615  }
2616 
2617  /*
2618  * Since all other constraint types throw errors, this must be a check
2619  * constraint. First, process the constraint expression and add an entry
2620  * to pg_constraint.
2621  */
2622 
2623  ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
2624  typTup->typbasetype, typTup->typtypmod,
2625  constr, NameStr(typTup->typname), constrAddr);
2626 
2627  /*
2628  * If requested to validate the constraint, test all values stored in the
2629  * attributes based on the domain the constraint is being added to.
2630  */
2631  if (!constr->skip_validation)
2632  validateDomainConstraint(domainoid, ccbin);
2633 
2634  ObjectAddressSet(address, TypeRelationId, domainoid);
2635 
2636  /* Clean up */
2637  heap_close(typrel, RowExclusiveLock);
2638 
2639  return address;
2640 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
static char * domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:3057
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_type * Form_pg_type
Definition: pg_type.h:247
#define nodeTag(nodeptr)
Definition: nodes.h:522
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3037
static void validateDomainConstraint(Oid domainoid, char *ccbin)
Definition: typecmds.c:2750
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
int errmsg(const char *fmt,...)
Definition: elog.c:797
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:455
#define NameStr(name)
Definition: c.h:576
ConstrType contype
Definition: parsenodes.h:2092
#define elog
Definition: elog.h:219
bool skip_validation
Definition: parsenodes.h:2135
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274

◆ AlterDomainDefault()

ObjectAddress AlterDomainDefault ( List names,
Node defaultRaw 
)

Definition at line 2194 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

2195 {
2196  TypeName *typename;
2197  Oid domainoid;
2198  HeapTuple tup;
2199  ParseState *pstate;
2200  Relation rel;
2201  char *defaultValue;
2202  Node *defaultExpr = NULL; /* NULL if no default specified */
2203  Datum new_record[Natts_pg_type];
2204  bool new_record_nulls[Natts_pg_type];
2205  bool new_record_repl[Natts_pg_type];
2206  HeapTuple newtuple;
2207  Form_pg_type typTup;
2208  ObjectAddress address;
2209 
2210  /* Make a TypeName so we can use standard type lookup machinery */
2211  typename = makeTypeNameFromNameList(names);
2212  domainoid = typenameTypeId(NULL, typename);
2213 
2214  /* Look up the domain in the type table */
2215  rel = heap_open(TypeRelationId, RowExclusiveLock);
2216 
2217  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2218  if (!HeapTupleIsValid(tup))
2219  elog(ERROR, "cache lookup failed for type %u", domainoid);
2220  typTup = (Form_pg_type) GETSTRUCT(tup);
2221 
2222  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2223  checkDomainOwner(tup);
2224 
2225  /* Setup new tuple */
2226  MemSet(new_record, (Datum) 0, sizeof(new_record));
2227  MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2228  MemSet(new_record_repl, false, sizeof(new_record_repl));
2229 
2230  /* Store the new default into the tuple */
2231  if (defaultRaw)
2232  {
2233  /* Create a dummy ParseState for transformExpr */
2234  pstate = make_parsestate(NULL);
2235 
2236  /*
2237  * Cook the colDef->raw_expr into an expression. Note: Name is
2238  * strictly for error message
2239  */
2240  defaultExpr = cookDefault(pstate, defaultRaw,
2241  typTup->typbasetype,
2242  typTup->typtypmod,
2243  NameStr(typTup->typname));
2244 
2245  /*
2246  * If the expression is just a NULL constant, we treat the command
2247  * like ALTER ... DROP DEFAULT. (But see note for same test in
2248  * DefineDomain.)
2249  */
2250  if (defaultExpr == NULL ||
2251  (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
2252  {
2253  /* Default is NULL, drop it */
2254  new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2255  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2256  new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2257  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2258  }
2259  else
2260  {
2261  /*
2262  * Expression must be stored as a nodeToString result, but we also
2263  * require a valid textual representation (mainly to make life
2264  * easier for pg_dump).
2265  */
2266  defaultValue = deparse_expression(defaultExpr,
2267  NIL, false, false);
2268 
2269  /*
2270  * Form an updated tuple with the new default and write it back.
2271  */
2272  new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2273 
2274  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2275  new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2276  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2277  }
2278  }
2279  else
2280  {
2281  /* ALTER ... DROP DEFAULT */
2282  new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2283  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2284  new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2285  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2286  }
2287 
2288  newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2289  new_record, new_record_nulls,
2290  new_record_repl);
2291 
2292  CatalogTupleUpdate(rel, &tup->t_self, newtuple);
2293 
2294  /* Rebuild dependencies */
2295  GenerateTypeDependencies(typTup->typnamespace,
2296  domainoid,
2297  InvalidOid, /* typrelid is n/a */
2298  0, /* relation kind is n/a */
2299  typTup->typowner,
2300  typTup->typinput,
2301  typTup->typoutput,
2302  typTup->typreceive,
2303  typTup->typsend,
2304  typTup->typmodin,
2305  typTup->typmodout,
2306  typTup->typanalyze,
2307  InvalidOid,
2308  false, /* a domain isn't an implicit array */
2309  typTup->typbasetype,
2310  typTup->typcollation,
2311  defaultExpr,
2312  true); /* Rebuild is true */
2313 
2314  InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2315 
2316  ObjectAddressSet(address, TypeRelationId, domainoid);
2317 
2318  /* Clean up */
2319  heap_close(rel, NoLock);
2320  heap_freetuple(newtuple);
2321 
2322  return address;
2323 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define RelationGetDescr(relation)
Definition: rel.h:433
Definition: nodes.h:517
#define MemSet(start, val, len)
Definition: c.h:908
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
Node * cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname)
Definition: heap.c:2815
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
uintptr_t Datum
Definition: postgres.h:365
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3071
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
FormData_pg_type * Form_pg_type
Definition: pg_type.h:247
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3037
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:455
#define NameStr(name)
Definition: c.h:576
#define CStringGetTextDatum(s)
Definition: builtins.h:95
char * nodeToString(const void *obj)
Definition: outfuncs.c:4331
#define elog
Definition: elog.h:219
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1173
void GenerateTypeDependencies(Oid typeNamespace, Oid typeObjectId, Oid relationOid, char relationKind, Oid owner, Oid inputProcedure, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, Oid typmodinProcedure, Oid typmodoutProcedure, Oid analyzeProcedure, Oid elementType, bool isImplicitArray, Oid baseType, Oid typeCollation, Node *defaultExpr, bool rebuild)
Definition: pg_type.c:511
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274

◆ AlterDomainDropConstraint()

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

Definition at line 2449 of file typecmds.c.

References BTEqualStrategyNumber, checkDomainOwner(), ObjectAddress::classId, ConstraintTypidIndexId, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvalidObjectAddress, makeTypeNameFromNameList(), NameStr, NoLock, NOTICE, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, performDeletion(), RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, systable_beginscan(), systable_endscan(), systable_getnext(), TypeNameToString(), typenameTypeId(), and TYPEOID.

Referenced by ProcessUtilitySlow().

2451 {
2452  TypeName *typename;
2453  Oid domainoid;
2454  HeapTuple tup;
2455  Relation rel;
2456  Relation conrel;
2457  SysScanDesc conscan;
2458  ScanKeyData key[1];
2459  HeapTuple contup;
2460  bool found = false;
2462 
2463  /* Make a TypeName so we can use standard type lookup machinery */
2464  typename = makeTypeNameFromNameList(names);
2465  domainoid = typenameTypeId(NULL, typename);
2466 
2467  /* Look up the domain in the type table */
2468  rel = heap_open(TypeRelationId, RowExclusiveLock);
2469 
2470  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2471  if (!HeapTupleIsValid(tup))
2472  elog(ERROR, "cache lookup failed for type %u", domainoid);
2473 
2474  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2475  checkDomainOwner(tup);
2476 
2477  /* Grab an appropriate lock on the pg_constraint relation */
2478  conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2479 
2480  /* Use the index to scan only constraints of the target relation */
2481  ScanKeyInit(&key[0],
2482  Anum_pg_constraint_contypid,
2483  BTEqualStrategyNumber, F_OIDEQ,
2485 
2486  conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2487  NULL, 1, key);
2488 
2489  /*
2490  * Scan over the result set, removing any matching entries.
2491  */
2492  while ((contup = systable_getnext(conscan)) != NULL)
2493  {
2495 
2496  if (strcmp(NameStr(con->conname), constrName) == 0)
2497  {
2498  ObjectAddress conobj;
2499 
2500  conobj.classId = ConstraintRelationId;
2501  conobj.objectId = HeapTupleGetOid(contup);
2502  conobj.objectSubId = 0;
2503 
2504  performDeletion(&conobj, behavior, 0);
2505  found = true;
2506  }
2507  }
2508 
2509  ObjectAddressSet(address, TypeRelationId, domainoid);
2510 
2511  /* Clean up after the scan */
2512  systable_endscan(conscan);
2513  heap_close(conrel, RowExclusiveLock);
2514 
2515  heap_close(rel, NoLock);
2516 
2517  if (!found)
2518  {
2519  if (!missing_ok)
2520  ereport(ERROR,
2521  (errcode(ERRCODE_UNDEFINED_OBJECT),
2522  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2523  constrName, TypeNameToString(typename))));
2524  else
2525  ereport(NOTICE,
2526  (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2527  constrName, TypeNameToString(typename))));
2528  }
2529 
2530  return address;
2531 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:459
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define ConstraintTypidIndexId
Definition: indexing.h:127
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:331
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:300
#define ereport(elevel, rest)
Definition: elog.h:122
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define NOTICE
Definition: elog.h:37
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3037
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:455
#define NameStr(name)
Definition: c.h:576
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274

◆ AlterDomainNotNull()

ObjectAddress AlterDomainNotNull ( List names,
bool  notNull 
)

Definition at line 2333 of file typecmds.c.

References attnum, RelToCheck::atts, CatalogTupleUpdate(), checkDomainOwner(), elog, ereport, errcode(), errmsg(), ERROR, errtablecol(), ForwardScanDirection, get_rels_with_domain(), GetLatestSnapshot(), GETSTRUCT, heap_attisnull(), heap_beginscan(), heap_close, heap_endscan(), heap_freetuple(), heap_getnext(), heap_open(), HeapTupleIsValid, i, InvalidObjectAddress, InvokeObjectPostAlterHook, lfirst, makeTypeNameFromNameList(), NameStr, RelToCheck::natts, NoLock, ObjectAddressSet, ObjectIdGetDatum, RegisterSnapshot(), RelToCheck::rel, RelationGetDescr, RelationGetRelationName, RowExclusiveLock, SearchSysCacheCopy1, ShareLock, HeapTupleData::t_self, TupleDescAttr, typenameTypeId(), TYPEOID, and UnregisterSnapshot().

Referenced by ProcessUtilitySlow().

2334 {
2335  TypeName *typename;
2336  Oid domainoid;
2337  Relation typrel;
2338  HeapTuple tup;
2339  Form_pg_type typTup;
2341 
2342  /* Make a TypeName so we can use standard type lookup machinery */
2343  typename = makeTypeNameFromNameList(names);
2344  domainoid = typenameTypeId(NULL, typename);
2345 
2346  /* Look up the domain in the type table */
2347  typrel = heap_open(TypeRelationId, RowExclusiveLock);
2348 
2349  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2350  if (!HeapTupleIsValid(tup))
2351  elog(ERROR, "cache lookup failed for type %u", domainoid);
2352  typTup = (Form_pg_type) GETSTRUCT(tup);
2353 
2354  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2355  checkDomainOwner(tup);
2356 
2357  /* Is the domain already set to the desired constraint? */
2358  if (typTup->typnotnull == notNull)
2359  {
2360  heap_close(typrel, RowExclusiveLock);
2361  return address;
2362  }
2363 
2364  /* Adding a NOT NULL constraint requires checking existing columns */
2365  if (notNull)
2366  {
2367  List *rels;
2368  ListCell *rt;
2369 
2370  /* Fetch relation list with attributes based on this domain */
2371  /* ShareLock is sufficient to prevent concurrent data changes */
2372 
2373  rels = get_rels_with_domain(domainoid, ShareLock);
2374 
2375  foreach(rt, rels)
2376  {
2377  RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2378  Relation testrel = rtc->rel;
2379  TupleDesc tupdesc = RelationGetDescr(testrel);
2380  HeapScanDesc scan;
2381  HeapTuple tuple;
2382  Snapshot snapshot;
2383 
2384  /* Scan all tuples in this relation */
2385  snapshot = RegisterSnapshot(GetLatestSnapshot());
2386  scan = heap_beginscan(testrel, snapshot, 0, NULL);
2387  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2388  {
2389  int i;
2390 
2391  /* Test attributes that are of the domain */
2392  for (i = 0; i < rtc->natts; i++)
2393  {
2394  int attnum = rtc->atts[i];
2395  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2396 
2397  if (heap_attisnull(tuple, attnum, tupdesc))
2398  {
2399  /*
2400  * In principle the auxiliary information for this
2401  * error should be errdatatype(), but errtablecol()
2402  * seems considerably more useful in practice. Since
2403  * this code only executes in an ALTER DOMAIN command,
2404  * the client should already know which domain is in
2405  * question.
2406  */
2407  ereport(ERROR,
2408  (errcode(ERRCODE_NOT_NULL_VIOLATION),
2409  errmsg("column \"%s\" of table \"%s\" contains null values",
2410  NameStr(attr->attname),
2411  RelationGetRelationName(testrel)),
2412  errtablecol(testrel, attnum)));
2413  }
2414  }
2415  }
2416  heap_endscan(scan);
2417  UnregisterSnapshot(snapshot);
2418 
2419  /* Close each rel after processing, but keep lock */
2420  heap_close(testrel, NoLock);
2421  }
2422  }
2423 
2424  /*
2425  * Okay to update pg_type row. We can scribble on typTup because it's a
2426  * copy.
2427  */
2428  typTup->typnotnull = notNull;
2429 
2430  CatalogTupleUpdate(typrel, &tup->t_self, tup);
2431 
2432  InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2433 
2434  ObjectAddressSet(address, TypeRelationId, domainoid);
2435 
2436  /* Clean up */
2437  heap_freetuple(tup);
2438  heap_close(typrel, RowExclusiveLock);
2439 
2440  return address;
2441 }
int * atts
Definition: typecmds.c:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1572
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:863
#define RelationGetDescr(relation)
Definition: rel.h:433
Relation rel
Definition: typecmds.c:76
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
int errcode(int sqlerrcode)
Definition: elog.c:575
bool heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
Definition: heaptuple.c:397
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:441
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:905
static List * get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
Definition: typecmds.c:2868
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1835
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
int16 attnum
Definition: pg_attribute.h:79
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:106
int errtablecol(Relation rel, int attnum)
Definition: relcache.c:5209
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
FormData_pg_type * Form_pg_type
Definition: pg_type.h:247
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:379
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3037
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ShareLock
Definition: lockdefs.h:41
int i
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:455
#define NameStr(name)
Definition: c.h:576
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
HeapScanDesc heap_beginscan(Relation relation, Snapshot snapshot, int nkeys, ScanKey key)
Definition: heapam.c:1404
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274
int natts
Definition: typecmds.c:77

◆ AlterDomainValidateConstraint()

ObjectAddress AlterDomainValidateConstraint ( List names,
const char *  constrName 
)

Definition at line 2648 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

2649 {
2650  TypeName *typename;
2651  Oid domainoid;
2652  Relation typrel;
2653  Relation conrel;
2654  HeapTuple tup;
2655  Form_pg_constraint con = NULL;
2656  Form_pg_constraint copy_con;
2657  char *conbin;
2658  SysScanDesc scan;
2659  Datum val;
2660  bool found = false;
2661  bool isnull;
2662  HeapTuple tuple;
2663  HeapTuple copyTuple;
2664  ScanKeyData key;
2665  ObjectAddress address;
2666 
2667  /* Make a TypeName so we can use standard type lookup machinery */
2668  typename = makeTypeNameFromNameList(names);
2669  domainoid = typenameTypeId(NULL, typename);
2670 
2671  /* Look up the domain in the type table */
2672  typrel = heap_open(TypeRelationId, AccessShareLock);
2673 
2674  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2675  if (!HeapTupleIsValid(tup))
2676  elog(ERROR, "cache lookup failed for type %u", domainoid);
2677 
2678  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2679  checkDomainOwner(tup);
2680 
2681  /*
2682  * Find and check the target constraint
2683  */
2684  conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
2685  ScanKeyInit(&key,
2686  Anum_pg_constraint_contypid,
2687  BTEqualStrategyNumber, F_OIDEQ,
2688  ObjectIdGetDatum(domainoid));
2690  true, NULL, 1, &key);
2691 
2692  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2693  {
2694  con = (Form_pg_constraint) GETSTRUCT(tuple);
2695  if (strcmp(NameStr(con->conname), constrName) == 0)
2696  {
2697  found = true;
2698  break;
2699  }
2700  }
2701 
2702  if (!found)
2703  ereport(ERROR,
2704  (errcode(ERRCODE_UNDEFINED_OBJECT),
2705  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2706  constrName, TypeNameToString(typename))));
2707 
2708  if (con->contype != CONSTRAINT_CHECK)
2709  ereport(ERROR,
2710  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2711  errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2712  constrName, TypeNameToString(typename))));
2713 
2714  val = SysCacheGetAttr(CONSTROID, tuple,
2715  Anum_pg_constraint_conbin,
2716  &isnull);
2717  if (isnull)
2718  elog(ERROR, "null conbin for constraint %u",
2719  HeapTupleGetOid(tuple));
2720  conbin = TextDatumGetCString(val);
2721 
2722  validateDomainConstraint(domainoid, conbin);
2723 
2724  /*
2725  * Now update the catalog, while we have the door open.
2726  */
2727  copyTuple = heap_copytuple(tuple);
2728  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2729  copy_con->convalidated = true;
2730  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
2731 
2732  InvokeObjectPostAlterHook(ConstraintRelationId,
2733  HeapTupleGetOid(copyTuple), 0);
2734 
2735  ObjectAddressSet(address, TypeRelationId, domainoid);
2736 
2737  heap_freetuple(copyTuple);
2738 
2739  systable_endscan(scan);
2740 
2741  heap_close(typrel, AccessShareLock);
2742  heap_close(conrel, RowExclusiveLock);
2743 
2744  ReleaseSysCache(tup);
2745 
2746  return address;
2747 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:722
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:459
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
#define ConstraintTypidIndexId
Definition: indexing.h:127
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:331
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define TextDatumGetCString(d)
Definition: builtins.h:96
uintptr_t Datum
Definition: postgres.h:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:3037
static void validateDomainConstraint(Oid domainoid, char *ccbin)
Definition: typecmds.c:2750
int errmsg(const char *fmt,...)
Definition: elog.c:797
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:455
#define NameStr(name)
Definition: c.h:576
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
long val
Definition: informix.c:689
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274

◆ AlterEnum()

ObjectAddress AlterEnum ( AlterEnumStmt stmt,
bool  isTopLevel 
)

Definition at line 1276 of file typecmds.c.

References AddEnumLabel(), checkEnumOwner(), elog, ERROR, GetCurrentTransactionId(), HEAP_UPDATED, HeapTupleHeaderGetXmin, HeapTupleIsValid, InvokeObjectPostAlterHook, makeTypeNameFromNameList(), AlterEnumStmt::newVal, AlterEnumStmt::newValIsAfter, AlterEnumStmt::newValNeighbor, ObjectAddressSet, ObjectIdGetDatum, AlterEnumStmt::oldVal, PreventInTransactionBlock(), ReleaseSysCache(), RenameEnumLabel(), SearchSysCache1(), AlterEnumStmt::skipIfNewValExists, HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, AlterEnumStmt::typeName, typenameTypeId(), and TYPEOID.

Referenced by ProcessUtilitySlow().

1277 {
1278  Oid enum_type_oid;
1279  TypeName *typename;
1280  HeapTuple tup;
1281  ObjectAddress address;
1282 
1283  /* Make a TypeName so we can use standard type lookup machinery */
1284  typename = makeTypeNameFromNameList(stmt->typeName);
1285  enum_type_oid = typenameTypeId(NULL, typename);
1286 
1287  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1288  if (!HeapTupleIsValid(tup))
1289  elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1290 
1291  /* Check it's an enum and check user has permission to ALTER the enum */
1292  checkEnumOwner(tup);
1293 
1294  if (stmt->oldVal)
1295  {
1296  /* Rename an existing label */
1297  RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
1298  }
1299  else
1300  {
1301  /* Add a new label */
1302 
1303  /*
1304  * Ordinarily we disallow adding values within transaction blocks,
1305  * because we can't cope with enum OID values getting into indexes and
1306  * then having their defining pg_enum entries go away. However, it's
1307  * okay if the enum type was created in the current transaction, since
1308  * then there can be no such indexes that wouldn't themselves go away
1309  * on rollback. (We support this case because pg_dump
1310  * --binary-upgrade needs it.) We test this by seeing if the pg_type
1311  * row has xmin == current XID and is not HEAP_UPDATED. If it is
1312  * HEAP_UPDATED, we can't be sure whether the type was created or only
1313  * modified in this xact. So we are disallowing some cases that could
1314  * theoretically be safe; but fortunately pg_dump only needs the
1315  * simplest case.
1316  */
1318  !(tup->t_data->t_infomask & HEAP_UPDATED))
1319  /* safe to do inside transaction block */ ;
1320  else
1321  PreventInTransactionBlock(isTopLevel, "ALTER TYPE ... ADD");
1322 
1323  AddEnumLabel(enum_type_oid, stmt->newVal,
1324  stmt->newValNeighbor, stmt->newValIsAfter,
1325  stmt->skipIfNewValExists);
1326  }
1327 
1328  InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1329 
1330  ObjectAddressSet(address, TypeRelationId, enum_type_oid);
1331 
1332  ReleaseSysCache(tup);
1333 
1334  return address;
1335 }
#define HEAP_UPDATED
Definition: htup_details.h:206
unsigned int Oid
Definition: postgres_ext.h:31
HeapTupleHeader t_data
Definition: htup.h:68
char * newValNeighbor
Definition: parsenodes.h:3024
static void checkEnumOwner(HeapTuple tup)
Definition: typecmds.c:1345
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
List * typeName
Definition: parsenodes.h:3021
void AddEnumLabel(Oid enumTypeOid, const char *newVal, const char *neighbor, bool newValIsAfter, bool skipIfExists)
Definition: pg_enum.c:179
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:417
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
Definition: xact.c:3153
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
void RenameEnumLabel(Oid enumTypeOid, const char *oldVal, const char *newVal)
Definition: pg_enum.c:471
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
bool skipIfNewValExists
Definition: parsenodes.h:3026
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
bool newValIsAfter
Definition: parsenodes.h:3025
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:318
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:455
#define elog
Definition: elog.h:219
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274

◆ AlterTypeNamespace()

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

Definition at line 3503 of file typecmds.c.

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

3505 {
3506  TypeName *typename;
3507  Oid typeOid;
3508  Oid nspOid;
3509  Oid oldNspOid;
3510  ObjectAddresses *objsMoved;
3511  ObjectAddress myself;
3512 
3513  /* Make a TypeName so we can use standard type lookup machinery */
3514  typename = makeTypeNameFromNameList(names);
3515  typeOid = typenameTypeId(NULL, typename);
3516 
3517  /* Don't allow ALTER DOMAIN on a type */
3518  if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3519  ereport(ERROR,
3520  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3521  errmsg("%s is not a domain",
3522  format_type_be(typeOid))));
3523 
3524  /* get schema OID and check its permissions */
3525  nspOid = LookupCreationNamespace(newschema);
3526 
3527  objsMoved = new_object_addresses();
3528  oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3529  free_object_addresses(objsMoved);
3530 
3531  if (oldschema)
3532  *oldschema = oldNspOid;
3533 
3534  ObjectAddressSet(myself, TypeRelationId, typeOid);
3535 
3536  return myself;
3537 }
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2915
int errcode(int sqlerrcode)
Definition: elog.c:575
char get_typtype(Oid typid)
Definition: lsyscache.c:2383
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2130
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2401
unsigned int Oid
Definition: postgres_ext.h:31
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: typecmds.c:3540
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
int errmsg(const char *fmt,...)
Definition: elog.c:797
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:455
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274

◆ AlterTypeNamespace_oid()

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

Definition at line 3540 of file typecmds.c.

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

Referenced by AlterObjectNamespace_oid(), and AlterTypeNamespace().

3541 {
3542  Oid elemOid;
3543 
3544  /* check permissions on type */
3545  if (!pg_type_ownercheck(typeOid, GetUserId()))
3547 
3548  /* don't allow direct alteration of array types */
3549  elemOid = get_element_type(typeOid);
3550  if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3551  ereport(ERROR,
3552  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3553  errmsg("cannot alter array type %s",
3554  format_type_be(typeOid)),
3555  errhint("You can alter type %s, which will alter the array type as well.",
3556  format_type_be(elemOid))));
3557 
3558  /* and do the work */
3559  return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3560 }
int errhint(const char *fmt,...)
Definition: elog.c:987
Oid GetUserId(void)
Definition: miscinit.c:379
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2502
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2530
int errcode(int sqlerrcode)
Definition: elog.c:575
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3578
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
unsigned int Oid
Definition: postgres_ext.h:31
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4774
#define OidIsValid(objectId)
Definition: c.h:605
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3659
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ AlterTypeNamespaceInternal()

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

Definition at line 3578 of file typecmds.c.

References add_exact_object_address(), AlterConstraintNamespaces(), AlterRelationNamespaceInternal(), AlterTypeNamespaceInternal(), 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_close, heap_freetuple(), heap_open(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHook, NameGetDatum, NameStr, object_address_present(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, RowExclusiveLock, SearchSysCacheCopy1, SearchSysCacheExists2, HeapTupleData::t_self, TYPENAMENSP, and TYPEOID.

Referenced by AlterSeqNamespaces(), AlterTableNamespaceInternal(), AlterTypeNamespace_oid(), and AlterTypeNamespaceInternal().

3582 {
3583  Relation rel;
3584  HeapTuple tup;
3585  Form_pg_type typform;
3586  Oid oldNspOid;
3587  Oid arrayOid;
3588  bool isCompositeType;
3589  ObjectAddress thisobj;
3590 
3591  /*
3592  * Make sure we haven't moved this object previously.
3593  */
3594  thisobj.classId = TypeRelationId;
3595  thisobj.objectId = typeOid;
3596  thisobj.objectSubId = 0;
3597 
3598  if (object_address_present(&thisobj, objsMoved))
3599  return InvalidOid;
3600 
3601  rel = heap_open(TypeRelationId, RowExclusiveLock);
3602 
3603  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3604  if (!HeapTupleIsValid(tup))
3605  elog(ERROR, "cache lookup failed for type %u", typeOid);
3606  typform = (Form_pg_type) GETSTRUCT(tup);
3607 
3608  oldNspOid = typform->typnamespace;
3609  arrayOid = typform->typarray;
3610 
3611  /* If the type is already there, we scan skip these next few checks. */
3612  if (oldNspOid != nspOid)
3613  {
3614  /* common checks on switching namespaces */
3615  CheckSetNamespace(oldNspOid, nspOid);
3616 
3617  /* check for duplicate name (more friendly than unique-index failure) */
3619  NameGetDatum(&typform->typname),
3620  ObjectIdGetDatum(nspOid)))
3621  ereport(ERROR,
3623  errmsg("type \"%s\" already exists in schema \"%s\"",
3624  NameStr(typform->typname),
3625  get_namespace_name(nspOid))));
3626  }
3627 
3628  /* Detect whether type is a composite type (but not a table rowtype) */
3629  isCompositeType =
3630  (typform->typtype == TYPTYPE_COMPOSITE &&
3631  get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3632 
3633  /* Enforce not-table-type if requested */
3634  if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3635  errorOnTableType)
3636  ereport(ERROR,
3637  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3638  errmsg("%s is a table's row type",
3639  format_type_be(typeOid)),
3640  errhint("Use ALTER TABLE instead.")));
3641 
3642  if (oldNspOid != nspOid)
3643  {
3644  /* OK, modify the pg_type row */
3645 
3646  /* tup is a copy, so we can scribble directly on it */
3647  typform->typnamespace = nspOid;
3648 
3649  CatalogTupleUpdate(rel, &tup->t_self, tup);
3650  }
3651 
3652  /*
3653  * Composite types have pg_class entries.
3654  *
3655  * We need to modify the pg_class tuple as well to reflect the change of
3656  * schema.
3657  */
3658  if (isCompositeType)
3659  {
3660  Relation classRel;
3661 
3662  classRel = heap_open(RelationRelationId, RowExclusiveLock);
3663 
3664  AlterRelationNamespaceInternal(classRel, typform->typrelid,
3665  oldNspOid, nspOid,
3666  false, objsMoved);
3667 
3668  heap_close(classRel, RowExclusiveLock);
3669 
3670  /*
3671  * Check for constraints associated with the composite type (we don't
3672  * currently support this, but probably will someday).
3673  */
3674  AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3675  nspOid, false, objsMoved);
3676  }
3677  else
3678  {
3679  /* If it's a domain, it might have constraints */
3680  if (typform->typtype == TYPTYPE_DOMAIN)
3681  AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
3682  objsMoved);
3683  }
3684 
3685  /*
3686  * Update dependency on schema, if any --- a table rowtype has not got
3687  * one, and neither does an implicit array.
3688  */
3689  if (oldNspOid != nspOid &&
3690  (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3691  !isImplicitArray)
3692  if (changeDependencyFor(TypeRelationId, typeOid,
3693  NamespaceRelationId, oldNspOid, nspOid) != 1)
3694  elog(ERROR, "failed to change schema dependency for type %s",
3695  format_type_be(typeOid));
3696 
3697  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3698 
3699  heap_freetuple(tup);
3700 
3702 
3703  add_exact_object_address(&thisobj, objsMoved);
3704 
3705  /* Recursively alter the associated array type, if any */
3706  if (OidIsValid(arrayOid))
3707  AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
3708 
3709  return oldNspOid;
3710 }
#define NameGetDatum(X)
Definition: postgres.h:578
int errhint(const char *fmt,...)
Definition: elog.c:987
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2245
int errcode(int sqlerrcode)
Definition: elog.c:575
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3578
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2185
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2947
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
FormData_pg_type * Form_pg_type
Definition: pg_type.h:247
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:184
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12961
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
int errmsg(const char *fmt,...)
Definition: elog.c:797
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:295
#define NameStr(name)
Definition: c.h:576
#define elog
Definition: elog.h:219
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32

◆ AlterTypeOwner()

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

Definition at line 3299 of file typecmds.c.

References ACL_CREATE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTypeOwner_oid(), check_is_member_of_role(), ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), get_array_type(), get_namespace_name(), get_rel_relkind(), GETSTRUCT, GetUserId(), heap_close, heap_copytuple(), heap_open(), HeapTupleGetOid, LookupTypeName(), makeTypeNameFromNameList(), OBJECT_DOMAIN, OBJECT_SCHEMA, ObjectAddressSet, OidIsValid, pg_namespace_aclcheck(), pg_type_ownercheck(), ReleaseSysCache(), RowExclusiveLock, superuser(), TypeNameToString(), and typeTypeId().

Referenced by ExecAlterOwnerStmt().

3300 {
3301  TypeName *typename;
3302  Oid typeOid;
3303  Relation rel;
3304  HeapTuple tup;
3305  HeapTuple newtup;
3306  Form_pg_type typTup;
3307  AclResult aclresult;
3308  ObjectAddress address;
3309 
3310  rel = heap_open(TypeRelationId, RowExclusiveLock);
3311 
3312  /* Make a TypeName so we can use standard type lookup machinery */
3313  typename = makeTypeNameFromNameList(names);
3314 
3315  /* Use LookupTypeName here so that shell types can be processed */
3316  tup = LookupTypeName(NULL, typename, NULL, false);
3317  if (tup == NULL)
3318  ereport(ERROR,
3319  (errcode(ERRCODE_UNDEFINED_OBJECT),
3320  errmsg("type \"%s\" does not exist",
3321  TypeNameToString(typename))));
3322  typeOid = typeTypeId(tup);
3323 
3324  /* Copy the syscache entry so we can scribble on it below */
3325  newtup = heap_copytuple(tup);
3326  ReleaseSysCache(tup);
3327  tup = newtup;
3328  typTup = (Form_pg_type) GETSTRUCT(tup);
3329 
3330  /* Don't allow ALTER DOMAIN on a type */
3331  if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3332  ereport(ERROR,
3333  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3334  errmsg("%s is not a domain",
3335  format_type_be(typeOid))));
3336 
3337  /*
3338  * If it's a composite type, we need to check that it really is a
3339  * free-standing composite type, and not a table's rowtype. We want people
3340  * to use ALTER TABLE not ALTER TYPE for that case.
3341  */
3342  if (typTup->typtype == TYPTYPE_COMPOSITE &&
3343  get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3344  ereport(ERROR,
3345  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3346  errmsg("%s is a table's row type",
3347  format_type_be(typeOid)),
3348  errhint("Use ALTER TABLE instead.")));
3349 
3350  /* don't allow direct alteration of array types, either */
3351  if (OidIsValid(typTup->typelem) &&
3352  get_array_type(typTup->typelem) == typeOid)
3353  ereport(ERROR,
3354  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3355  errmsg("cannot alter array type %s",
3356  format_type_be(typeOid)),
3357  errhint("You can alter type %s, which will alter the array type as well.",
3358  format_type_be(typTup->typelem))));
3359 
3360  /*
3361  * If the new owner is the same as the existing owner, consider the
3362  * command to have succeeded. This is for dump restoration purposes.
3363  */
3364  if (typTup->typowner != newOwnerId)
3365  {
3366  /* Superusers can always do it */
3367  if (!superuser())
3368  {
3369  /* Otherwise, must be owner of the existing object */
3372 
3373  /* Must be able to become new owner */
3374  check_is_member_of_role(GetUserId(), newOwnerId);
3375 
3376  /* New owner must have CREATE privilege on namespace */
3377  aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3378  newOwnerId,
3379  ACL_CREATE);
3380  if (aclresult != ACLCHECK_OK)
3381  aclcheck_error(aclresult, OBJECT_SCHEMA,
3382  get_namespace_name(typTup->typnamespace));
3383  }
3384 
3385  AlterTypeOwner_oid(typeOid, newOwnerId, true);
3386  }
3387 
3388  ObjectAddressSet(address, TypeRelationId, typeOid);
3389 
3390  /* Clean up */
3392 
3393  return address;
3394 }
Type LookupTypeName(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, bool missing_ok)
Definition: parse_type.c:57
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:722
int errhint(const char *fmt,...)
Definition: elog.c:987
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
Oid GetUserId(void)
Definition: miscinit.c:379
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:459
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2530
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4774
#define OidIsValid(objectId)
Definition: c.h:605
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4686
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3659
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition: typecmds.c:3408
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
#define RowExclusiveLock
Definition: lockdefs.h:38
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4879
#define ereport(elevel, rest)
Definition: elog.h:122
AclResult
Definition: acl.h:178
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
FormData_pg_type * Form_pg_type
Definition: pg_type.h:247
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
int errmsg(const char *fmt,...)
Definition: elog.c:797
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:455
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712
Oid typeTypeId(Type tp)
Definition: parse_type.c:571

◆ AlterTypeOwner_oid()

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

Definition at line 3408 of file typecmds.c.

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

Referenced by AlterTypeOwner(), and shdepReassignOwned().

3409 {
3410  Relation rel;
3411  HeapTuple tup;
3412  Form_pg_type typTup;
3413 
3414  rel = heap_open(TypeRelationId, RowExclusiveLock);
3415 
3416  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3417  if (!HeapTupleIsValid(tup))
3418  elog(ERROR, "cache lookup failed for type %u", typeOid);
3419  typTup = (Form_pg_type) GETSTRUCT(tup);
3420 
3421  /*
3422  * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3423  * the pg_class entry properly. That will call back to
3424  * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3425  */
3426  if (typTup->typtype == TYPTYPE_COMPOSITE)
3427  ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3428  else
3429  AlterTypeOwnerInternal(typeOid, newOwnerId);
3430 
3431  /* Update owner dependency reference */
3432  if (hasDependEntry)
3433  changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3434 
3435  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3436 
3437  ReleaseSysCache(tup);
3439 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3448
#define heap_close(r, l)
Definition: heapam.h:97
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:304
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:10241
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_type * Form_pg_type
Definition: pg_type.h:247
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define elog
Definition: elog.h:219

◆ AlterTypeOwnerInternal()

void AlterTypeOwnerInternal ( Oid  typeOid,
Oid  newOwnerId 
)

Definition at line 3448 of file typecmds.c.

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

Referenced by AlterTypeOwner_oid(), AlterTypeOwnerInternal(), and ATExecChangeOwner().

3449 {
3450  Relation rel;
3451  HeapTuple tup;
3452  Form_pg_type typTup;
3453  Datum repl_val[Natts_pg_type];
3454  bool repl_null[Natts_pg_type];
3455  bool repl_repl[Natts_pg_type];
3456  Acl *newAcl;
3457  Datum aclDatum;
3458  bool isNull;
3459 
3460  rel = heap_open(TypeRelationId, RowExclusiveLock);
3461 
3462  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3463  if (!HeapTupleIsValid(tup))
3464  elog(ERROR, "cache lookup failed for type %u", typeOid);
3465  typTup = (Form_pg_type) GETSTRUCT(tup);
3466 
3467  memset(repl_null, false, sizeof(repl_null));
3468  memset(repl_repl, false, sizeof(repl_repl));
3469 
3470  repl_repl[Anum_pg_type_typowner - 1] = true;
3471  repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
3472 
3473  aclDatum = heap_getattr(tup,
3474  Anum_pg_type_typacl,
3475  RelationGetDescr(rel),
3476  &isNull);
3477  /* Null ACLs do not require changes */
3478  if (!isNull)
3479  {
3480  newAcl = aclnewowner(DatumGetAclP(aclDatum),
3481  typTup->typowner, newOwnerId);
3482  repl_repl[Anum_pg_type_typacl - 1] = true;
3483  repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3484  }
3485 
3486  tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3487  repl_repl);
3488 
3489  CatalogTupleUpdate(rel, &tup->t_self, tup);
3490 
3491  /* If it has an array type, update that too */
3492  if (OidIsValid(typTup->typarray))
3493  AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
3494 
3495  /* Clean up */
3497 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
#define RelationGetDescr(relation)
Definition: rel.h:433
#define DatumGetAclP(X)
Definition: acl.h:121
#define PointerGetDatum(X)
Definition: postgres.h:539
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3448
#define heap_close(r, l)
Definition: heapam.h:97
#define OidIsValid(objectId)
Definition: c.h:605
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:786
uintptr_t Datum
Definition: postgres.h:365
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
FormData_pg_type * Form_pg_type
Definition: pg_type.h:247
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
#define elog
Definition: elog.h:219
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1173
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1052

◆ AssignTypeArrayOid()

Oid AssignTypeArrayOid ( void  )

Definition at line 2095 of file typecmds.c.

References AccessShareLock, binary_upgrade_next_array_pg_type_oid, ereport, errcode(), errmsg(), ERROR, GetNewOid(), heap_close, heap_open(), InvalidOid, IsBinaryUpgrade, and OidIsValid.

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

2096 {
2097  Oid type_array_oid;
2098 
2099  /* Use binary-upgrade override for pg_type.typarray? */
2100  if (IsBinaryUpgrade)
2101  {
2103  ereport(ERROR,
2104  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2105  errmsg("pg_type array OID value not set when in binary upgrade mode")));
2106 
2107  type_array_oid = binary_upgrade_next_array_pg_type_oid;
2109  }
2110  else
2111  {
2112  Relation pg_type = heap_open(TypeRelationId, AccessShareLock);
2113 
2114  type_array_oid = GetNewOid(pg_type);
2115  heap_close(pg_type, AccessShareLock);
2116  }
2117 
2118  return type_array_oid;
2119 }
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
bool IsBinaryUpgrade
Definition: globals.c:111
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
Oid GetNewOid(Relation relation)
Definition: catalog.c:293
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvalidOid
Definition: postgres_ext.h:36
Oid binary_upgrade_next_array_pg_type_oid
Definition: typecmds.c:83
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ checkDomainOwner()

void checkDomainOwner ( HeapTuple  tup)

Definition at line 3037 of file typecmds.c.

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

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

3038 {
3039  Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
3040 
3041  /* Check that this is actually a domain */
3042  if (typTup->typtype != TYPTYPE_DOMAIN)
3043  ereport(ERROR,
3044  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3045  errmsg("%s is not a domain",
3047 
3048  /* Permission check: must own type */
3051 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
Oid GetUserId(void)
Definition: miscinit.c:379
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4774
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3659
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
FormData_pg_type * Form_pg_type
Definition: pg_type.h:247
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712

◆ checkEnumOwner()

static void checkEnumOwner ( HeapTuple  tup)
static

Definition at line 1345 of file typecmds.c.

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

Referenced by AlterEnum().

1346 {
1347  Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1348 
1349  /* Check that this is actually an enum */
1350  if (typTup->typtype != TYPTYPE_ENUM)
1351  ereport(ERROR,
1352  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1353  errmsg("%s is not an enum",
1355 
1356  /* Permission check: must own type */
1359 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
Oid GetUserId(void)
Definition: miscinit.c:379
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4774
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3659
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
FormData_pg_type * Form_pg_type
Definition: pg_type.h:247
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:712

◆ DefineCompositeType()

ObjectAddress DefineCompositeType ( RangeVar typevar,
List coldeflist 
)

Definition at line 2136 of file typecmds.c.

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

2137 {
2138  CreateStmt *createStmt = makeNode(CreateStmt);
2139  Oid old_type_oid;
2140  Oid typeNamespace;
2141  ObjectAddress address;
2142 
2143  /*
2144  * now set the parameters for keys/inheritance etc. All of these are
2145  * uninteresting for composite types...
2146  */
2147  createStmt->relation = typevar;
2148  createStmt->tableElts = coldeflist;
2149  createStmt->inhRelations = NIL;
2150  createStmt->constraints = NIL;
2151  createStmt->options = NIL;
2152  createStmt->oncommit = ONCOMMIT_NOOP;
2153  createStmt->tablespacename = NULL;
2154  createStmt->if_not_exists = false;
2155 
2156  /*
2157  * Check for collision with an existing type name. If there is one and
2158  * it's an autogenerated array, we can rename it out of the way. This
2159  * check is here mainly to get a better error message about a "type"
2160  * instead of below about a "relation".
2161  */
2162  typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2163  NoLock, NULL);
2164  RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2165  old_type_oid =
2167  CStringGetDatum(createStmt->relation->relname),
2168  ObjectIdGetDatum(typeNamespace));
2169  if (OidIsValid(old_type_oid))
2170  {
2171  if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2172  ereport(ERROR,
2174  errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2175  }
2176 
2177  /*
2178  * Finally create the relation. This also creates the type.
2179  */
2180  DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2181  NULL);
2182 
2183  return address;
2184 }
RangeVar * relation
Definition: parsenodes.h:2014
#define NIL
Definition: pg_list.h:69
OnCommitAction oncommit
Definition: parsenodes.h:2023
List * inhRelations
Definition: parsenodes.h:2016
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition: namespace.c:634
#define GetSysCacheOid2(cacheId, key1, key2)
Definition: syscache.h:193
List * constraints
Definition: parsenodes.h:2021
bool if_not_exists
Definition: parsenodes.h:2025
char * relname
Definition: primnodes.h:69
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:832
#define NoLock
Definition: lockdefs.h:34
#define CStringGetDatum(X)
Definition: postgres.h:561
List * options
Definition: parsenodes.h:2022
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:519
#define ereport(elevel, rest)
Definition: elog.h:122
char * tablespacename
Definition: parsenodes.h:2024
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:527
#define InvalidOid
Definition: postgres_ext.h:36
List * tableElts
Definition: parsenodes.h:2015
#define makeNode(_type_)
Definition: nodes.h:565
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32

◆ DefineDomain()

ObjectAddress DefineDomain ( CreateDomainStmt stmt)

Definition at line 726 of file typecmds.c.

References ACL_CREATE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, TypeName::arrayBounds, AssignTypeArrayOid(), CreateDomainStmt::collClause, CollateClause::collname, CommandCounterIncrement(), CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_NOTNULL, CONSTR_NULL, CONSTR_PRIMARY, CONSTR_UNIQUE, CreateDomainStmt::constraints, Constraint::contype, cookDefault(), CStringGetDatum, deparse_expression(), domainAddConstraint(), CreateDomainStmt::domainname, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, format_type_be(), get_collation_oid(), get_namespace_name(), GETSTRUCT, GetSysCacheOid2, GetUserId(), HeapTupleGetOid, InvalidOid, Constraint::is_no_inherit, IsA, lfirst, list_length(), make_parsestate(), makeArrayTypeName(), moveArrayTypeName(), NIL, nodeTag, nodeToString(), OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, pfree(), pg_namespace_aclcheck(), pg_type_aclcheck(), QualifiedNameGetCreationNamespace(), Constraint::raw_expr, ReleaseSysCache(), SysCacheGetAttr(), TextDatumGetCString, TypeCreate(), CreateDomainStmt::typeName, TYPENAMENSP, TypeNameToString(), typenameType(), and TYPEOID.

Referenced by ProcessUtilitySlow().

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

◆ DefineEnum()

ObjectAddress DefineEnum ( CreateEnumStmt stmt)

Definition at line 1154 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

1155 {
1156  char *enumName;
1157  char *enumArrayName;
1158  Oid enumNamespace;
1159  AclResult aclresult;
1160  Oid old_type_oid;
1161  Oid enumArrayOid;
1162  ObjectAddress enumTypeAddr;
1163 
1164  /* Convert list of names to a name and namespace */
1165  enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1166  &enumName);
1167 
1168  /* Check we have creation rights in target namespace */
1169  aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1170  if (aclresult != ACLCHECK_OK)
1171  aclcheck_error(aclresult, OBJECT_SCHEMA,
1172  get_namespace_name(enumNamespace));
1173 
1174  /*
1175  * Check for collision with an existing type name. If there is one and
1176  * it's an autogenerated array, we can rename it out of the way.
1177  */
1178  old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1179  CStringGetDatum(enumName),
1180  ObjectIdGetDatum(enumNamespace));
1181  if (OidIsValid(old_type_oid))
1182  {
1183  if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1184  ereport(ERROR,
1186  errmsg("type \"%s\" already exists", enumName)));
1187  }
1188 
1189  /* Allocate OID for array type */
1190  enumArrayOid = AssignTypeArrayOid();
1191 
1192  /* Create the pg_type entry */
1193  enumTypeAddr =
1194  TypeCreate(InvalidOid, /* no predetermined type OID */
1195  enumName, /* type name */
1196  enumNamespace, /* namespace */
1197  InvalidOid, /* relation oid (n/a here) */
1198  0, /* relation kind (ditto) */
1199  GetUserId(), /* owner's ID */
1200  sizeof(Oid), /* internal size */
1201  TYPTYPE_ENUM, /* type-type (enum type) */
1202  TYPCATEGORY_ENUM, /* type-category (enum type) */
1203  false, /* enum types are never preferred */
1204  DEFAULT_TYPDELIM, /* array element delimiter */
1205  F_ENUM_IN, /* input procedure */
1206  F_ENUM_OUT, /* output procedure */
1207  F_ENUM_RECV, /* receive procedure */
1208  F_ENUM_SEND, /* send procedure */
1209  InvalidOid, /* typmodin procedure - none */
1210  InvalidOid, /* typmodout procedure - none */
1211  InvalidOid, /* analyze procedure - default */
1212  InvalidOid, /* element type ID */
1213  false, /* this is not an array type */
1214  enumArrayOid, /* array type we are about to create */
1215  InvalidOid, /* base type ID (only for domains) */
1216  NULL, /* never a default type value */
1217  NULL, /* binary default isn't sent either */
1218  true, /* always passed by value */
1219  'i', /* int alignment */
1220  'p', /* TOAST strategy always plain */
1221  -1, /* typMod (Domains only) */
1222  0, /* Array dimensions of typbasetype */
1223  false, /* Type NOT NULL */
1224  InvalidOid); /* type's collation */
1225 
1226  /* Enter the enum's values into pg_enum */
1227  EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
1228 
1229  /*
1230  * Create the array type that goes with it.
1231  */
1232  enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1233 
1234  TypeCreate(enumArrayOid, /* force assignment of this type OID */
1235  enumArrayName, /* type name */
1236  enumNamespace, /* namespace */
1237  InvalidOid, /* relation oid (n/a here) */
1238  0, /* relation kind (ditto) */
1239  GetUserId(), /* owner's ID */
1240  -1, /* internal size (always varlena) */
1241  TYPTYPE_BASE, /* type-type (base type) */
1242  TYPCATEGORY_ARRAY, /* type-category (array) */
1243  false, /* array types are never preferred */
1244  DEFAULT_TYPDELIM, /* array element delimiter */
1245  F_ARRAY_IN, /* input procedure */
1246  F_ARRAY_OUT, /* output procedure */
1247  F_ARRAY_RECV, /* receive procedure */
1248  F_ARRAY_SEND, /* send procedure */
1249  InvalidOid, /* typmodin procedure - none */
1250  InvalidOid, /* typmodout procedure - none */
1251  F_ARRAY_TYPANALYZE, /* analyze procedure */
1252  enumTypeAddr.objectId, /* element type ID */
1253  true, /* yes this is an array type */
1254  InvalidOid, /* no further array type */
1255  InvalidOid, /* base type ID */
1256  NULL, /* never a default type value */
1257  NULL, /* binary default isn't sent either */
1258  false, /* never passed by value */
1259  'i', /* enums have align i, so do their arrays */
1260  'x', /* ARRAY is always toastable */
1261  -1, /* typMod (Domains only) */
1262  0, /* Array dimensions of typbasetype */
1263  false, /* Type NOT NULL */
1264  InvalidOid); /* type's collation */
1265 
1266  pfree(enumArrayName);
1267 
1268  return enumTypeAddr;
1269 }
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:766
Oid GetUserId(void)
Definition: miscinit.c:379
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2975
int errcode(int sqlerrcode)
Definition: elog.c:575
void EnumValuesCreate(Oid enumTypeOid, List *vals)
Definition: pg_enum.c:49
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4686
#define GetSysCacheOid2(cacheId, key1, key2)
Definition: syscache.h:193
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:832
#define CStringGetDatum(X)
Definition: postgres.h:561
#define ereport(elevel, rest)
Definition: elog.h:122
AclResult
Definition: acl.h:178
#define InvalidOid
Definition: postgres_ext.h:36
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2095
int errmsg(const char *fmt,...)
Definition: elog.c:797
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 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:194
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32

◆ DefineRange()

ObjectAddress DefineRange ( CreateRangeStmt stmt)

Definition at line 1367 of file typecmds.c.

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, Assert, AssignTypeArrayOid(), CommandCounterIncrement(), CStringGetDatum, DEFAULT_TYPDELIM, defGetQualifiedName(), defGetTypeName(), DefElem::defname, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, 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(), makeRangeConstructors(), moveArrayTypeName(), NIL, OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, CreateRangeStmt::params, pfree(), pg_namespace_aclcheck(), QualifiedNameGetCreationNamespace(), RangeCreate(), type_is_collatable(), TypeCreate(), CreateRangeStmt::typeName, TYPENAMENSP, typenameTypeId(), and TypeShellMake().

Referenced by ProcessUtilitySlow().

1368 {
1369  char *typeName;
1370  Oid typeNamespace;
1371  Oid typoid;
1372  char *rangeArrayName;
1373  Oid rangeArrayOid;
1374  Oid rangeSubtype = InvalidOid;
1375  List *rangeSubOpclassName = NIL;
1376  List *rangeCollationName = NIL;
1377  List *rangeCanonicalName = NIL;
1378  List *rangeSubtypeDiffName = NIL;
1379  Oid rangeSubOpclass;
1380  Oid rangeCollation;
1381  regproc rangeCanonical;
1382  regproc rangeSubtypeDiff;
1383  int16 subtyplen;
1384  bool subtypbyval;
1385  char subtypalign;
1386  char alignment;
1387  AclResult aclresult;
1388  ListCell *lc;
1389  ObjectAddress address;
1390 
1391  /* Convert list of names to a name and namespace */
1392  typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1393  &typeName);
1394 
1395  /* Check we have creation rights in target namespace */
1396  aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1397  if (aclresult != ACLCHECK_OK)
1398  aclcheck_error(aclresult, OBJECT_SCHEMA,
1399  get_namespace_name(typeNamespace));
1400 
1401  /*
1402  * Look to see if type already exists.
1403  */
1404  typoid = GetSysCacheOid2(TYPENAMENSP,
1405  CStringGetDatum(typeName),
1406  ObjectIdGetDatum(typeNamespace));
1407 
1408  /*
1409  * If it's not a shell, see if it's an autogenerated array type, and if so
1410  * rename it out of the way.
1411  */
1412  if (OidIsValid(typoid) && get_typisdefined(typoid))
1413  {
1414  if (moveArrayTypeName(typoid, typeName, typeNamespace))
1415  typoid = InvalidOid;
1416  else
1417  ereport(ERROR,
1419  errmsg("type \"%s\" already exists", typeName)));
1420  }
1421 
1422  /*
1423  * If it doesn't exist, create it as a shell, so that the OID is known for
1424  * use in the range function definitions.
1425  */
1426  if (!OidIsValid(typoid))
1427  {
1428  address = TypeShellMake(typeName, typeNamespace, GetUserId());
1429  typoid = address.objectId;
1430  /* Make new shell type visible for modification below */
1432  }
1433 
1434  /* Extract the parameters from the parameter list */
1435  foreach(lc, stmt->params)
1436  {
1437  DefElem *defel = (DefElem *) lfirst(lc);
1438 
1439  if (strcmp(defel->defname, "subtype") == 0)
1440  {
1441  if (OidIsValid(rangeSubtype))
1442  ereport(ERROR,
1443  (errcode(ERRCODE_SYNTAX_ERROR),
1444  errmsg("conflicting or redundant options")));
1445  /* we can look up the subtype name immediately */
1446  rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1447  }
1448  else if (strcmp(defel->defname, "subtype_opclass") == 0)
1449  {
1450  if (rangeSubOpclassName != NIL)
1451  ereport(ERROR,
1452  (errcode(ERRCODE_SYNTAX_ERROR),
1453  errmsg("conflicting or redundant options")));
1454  rangeSubOpclassName = defGetQualifiedName(defel);
1455  }
1456  else if (strcmp(defel->defname, "collation") == 0)
1457  {
1458  if (rangeCollationName != NIL)
1459  ereport(ERROR,
1460  (errcode(ERRCODE_SYNTAX_ERROR),
1461  errmsg("conflicting or redundant options")));
1462  rangeCollationName = defGetQualifiedName(defel);
1463  }
1464  else if (strcmp(defel->defname, "canonical") == 0)
1465  {
1466  if (rangeCanonicalName != NIL)
1467  ereport(ERROR,
1468  (errcode(ERRCODE_SYNTAX_ERROR),
1469  errmsg("conflicting or redundant options")));
1470  rangeCanonicalName = defGetQualifiedName(defel);
1471  }
1472  else if (strcmp(defel->defname, "subtype_diff") == 0)
1473  {
1474  if (rangeSubtypeDiffName != NIL)
1475  ereport(ERROR,
1476  (errcode(ERRCODE_SYNTAX_ERROR),
1477  errmsg("conflicting or redundant options")));
1478  rangeSubtypeDiffName = defGetQualifiedName(defel);
1479  }
1480  else
1481  ereport(ERROR,
1482  (errcode(ERRCODE_SYNTAX_ERROR),
1483  errmsg("type attribute \"%s\" not recognized",
1484  defel->defname)));
1485  }
1486 
1487  /* Must have a subtype */
1488  if (!OidIsValid(rangeSubtype))
1489  ereport(ERROR,
1490  (errcode(ERRCODE_SYNTAX_ERROR),
1491  errmsg("type attribute \"subtype\" is required")));
1492  /* disallow ranges of pseudotypes */
1493  if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
1494  ereport(ERROR,
1495  (errcode(ERRCODE_DATATYPE_MISMATCH),
1496  errmsg("range subtype cannot be %s",
1497  format_type_be(rangeSubtype))));
1498 
1499  /* Identify subopclass */
1500  rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1501 
1502  /* Identify collation to use, if any */
1503  if (type_is_collatable(rangeSubtype))
1504  {
1505  if (rangeCollationName != NIL)
1506  rangeCollation = get_collation_oid(rangeCollationName, false);
1507  else
1508  rangeCollation = get_typcollation(rangeSubtype);
1509  }
1510  else
1511  {
1512  if (rangeCollationName != NIL)
1513  ereport(ERROR,
1514  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1515  errmsg("range collation specified but subtype does not support collation")));
1516  rangeCollation = InvalidOid;
1517  }
1518 
1519  /* Identify support functions, if provided */
1520  if (rangeCanonicalName != NIL)
1521  rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1522  typoid);
1523  else
1524  rangeCanonical = InvalidOid;
1525 
1526  if (rangeSubtypeDiffName != NIL)
1527  rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1528  rangeSubtype);
1529  else
1530  rangeSubtypeDiff = InvalidOid;
1531 
1532  get_typlenbyvalalign(rangeSubtype,
1533  &subtyplen, &subtypbyval, &subtypalign);
1534 
1535  /* alignment must be 'i' or 'd' for ranges */
1536  alignment = (subtypalign == 'd') ? 'd' : 'i';
1537 
1538  /* Allocate OID for array type */
1539  rangeArrayOid = AssignTypeArrayOid();
1540 
1541  /* Create the pg_type entry */
1542  address =
1543  TypeCreate(InvalidOid, /* no predetermined type OID */
1544  typeName, /* type name */
1545  typeNamespace, /* namespace */
1546  InvalidOid, /* relation oid (n/a here) */
1547  0, /* relation kind (ditto) */
1548  GetUserId(), /* owner's ID */
1549  -1, /* internal size (always varlena) */
1550  TYPTYPE_RANGE, /* type-type (range type) */
1551  TYPCATEGORY_RANGE, /* type-category (range type) */
1552  false, /* range types are never preferred */
1553  DEFAULT_TYPDELIM, /* array element delimiter */
1554  F_RANGE_IN, /* input procedure */
1555  F_RANGE_OUT, /* output procedure */
1556  F_RANGE_RECV, /* receive procedure */
1557  F_RANGE_SEND, /* send procedure */
1558  InvalidOid, /* typmodin procedure - none */
1559  InvalidOid, /* typmodout procedure - none */
1560  F_RANGE_TYPANALYZE, /* analyze procedure */
1561  InvalidOid, /* element type ID - none */
1562  false, /* this is not an array type */
1563  rangeArrayOid, /* array type we are about to create */
1564  InvalidOid, /* base type ID (only for domains) */
1565  NULL, /* never a default type value */
1566  NULL, /* no binary form available either */
1567  false, /* never passed by value */
1568  alignment, /* alignment */
1569  'x', /* TOAST strategy (always extended) */
1570  -1, /* typMod (Domains only) */
1571  0, /* Array dimensions of typbasetype */
1572  false, /* Type NOT NULL */
1573  InvalidOid); /* type's collation (ranges never have one) */
1574  Assert(typoid == address.objectId);
1575 
1576  /* Create the entry in pg_range */
1577  RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1578  rangeCanonical, rangeSubtypeDiff);
1579 
1580  /*
1581  * Create the array type that goes with it.
1582  */
1583  rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1584 
1585  TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1586  rangeArrayName, /* type name */
1587  typeNamespace, /* namespace */
1588  InvalidOid, /* relation oid (n/a here) */
1589  0, /* relation kind (ditto) */
1590  GetUserId(), /* owner's ID */
1591  -1, /* internal size (always varlena) */
1592  TYPTYPE_BASE, /* type-type (base type) */
1593  TYPCATEGORY_ARRAY, /* type-category (array) */
1594  false, /* array types are never preferred */
1595  DEFAULT_TYPDELIM, /* array element delimiter */
1596  F_ARRAY_IN, /* input procedure */
1597  F_ARRAY_OUT, /* output procedure */
1598  F_ARRAY_RECV, /* receive procedure */
1599  F_ARRAY_SEND, /* send procedure */
1600  InvalidOid, /* typmodin procedure - none */
1601  InvalidOid, /* typmodout procedure - none */
1602  F_ARRAY_TYPANALYZE, /* analyze procedure */
1603  typoid, /* element type ID */
1604  true, /* yes this is an array type */
1605  InvalidOid, /* no further array type */
1606  InvalidOid, /* base type ID */
1607  NULL, /* never a default type value */
1608  NULL, /* binary default isn't sent either */
1609  false, /* never passed by value */
1610  alignment, /* alignment - same as range's */
1611  'x', /* ARRAY is always toastable */
1612  -1, /* typMod (Domains only) */
1613  0, /* Array dimensions of typbasetype */
1614  false, /* Type NOT NULL */
1615  InvalidOid); /* typcollation */
1616 
1617  pfree(rangeArrayName);
1618 
1619  /* And create the constructor functions for this range type */
1620  makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1621 
1622  return address;
1623 }
signed short int16
Definition: c.h:312
#define NIL
Definition: pg_list.h:69
static void makeRangeConstructors(const char *name, Oid namespace, Oid rangeOid, Oid subtype)
Definition: typecmds.c:1635
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:766
Oid GetUserId(void)
Definition: miscinit.c:379
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2975
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2025
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:1927
int errcode(int sqlerrcode)
Definition: elog.c:575
char get_typtype(Oid typid)
Definition: lsyscache.c:2383
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
unsigned int Oid
Definition: postgres_ext.h:31
ObjectAddress TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
Definition: pg_type.c:55
#define OidIsValid(objectId)
Definition: c.h:605
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4686
#define GetSysCacheOid2(cacheId, key1, key2)
Definition: syscache.h:193
static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype)
Definition: typecmds.c:2047
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:255
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
void RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, Oid rangeSubOpclass, RegProcedure rangeCanonical, RegProcedure rangeSubDiff)
Definition: pg_range.c:37
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:832
#define CStringGetDatum(X)
Definition: postgres.h:561
#define ereport(elevel, rest)
Definition: elog.h:122
AclResult
Definition: acl.h:178
void CommandCounterIncrement(void)
Definition: xact.c:914
#define InvalidOid
Definition: postgres_ext.h:36
static Oid findRangeSubOpclass(List *opcname, Oid subtype)
Definition: typecmds.c:1967
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:2799
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
List * defGetQualifiedName(DefElem *def)
Definition: define.c:223
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2095
Oid regproc
Definition: c.h:471
int errmsg(const char *fmt,...)
Definition: elog.c:797
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 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:194
char * defname
Definition: parsenodes.h:730
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:2824
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3512
Definition: pg_list.h:45
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid)
Definition: typecmds.c:2006
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274

◆ DefineType()

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

Definition at line 113 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

114 {
115  char *typeName;
116  Oid typeNamespace;
117  int16 internalLength = -1; /* default: variable-length */
118  List *inputName = NIL;
119  List *outputName = NIL;
120  List *receiveName = NIL;
121  List *sendName = NIL;
122  List *typmodinName = NIL;
123  List *typmodoutName = NIL;
124  List *analyzeName = NIL;
125  char category = TYPCATEGORY_USER;
126  bool preferred = false;
127  char delimiter = DEFAULT_TYPDELIM;
128  Oid elemType = InvalidOid;
129  char *defaultValue = NULL;
130  bool byValue = false;
131  char alignment = 'i'; /* default alignment */
132  char storage = 'p'; /* default TOAST storage method */
133  Oid collation = InvalidOid;
134  DefElem *likeTypeEl = NULL;
135  DefElem *internalLengthEl = NULL;
136  DefElem *inputNameEl = NULL;
137  DefElem *outputNameEl = NULL;
138  DefElem *receiveNameEl = NULL;
139  DefElem *sendNameEl = NULL;
140  DefElem *typmodinNameEl = NULL;
141  DefElem *typmodoutNameEl = NULL;
142  DefElem *analyzeNameEl = NULL;
143  DefElem *categoryEl = NULL;
144  DefElem *preferredEl = NULL;
145  DefElem *delimiterEl = NULL;
146  DefElem *elemTypeEl = NULL;
147  DefElem *defaultValueEl = NULL;
148  DefElem *byValueEl = NULL;
149  DefElem *alignmentEl = NULL;
150  DefElem *storageEl = NULL;
151  DefElem *collatableEl = NULL;
152  Oid inputOid;
153  Oid outputOid;
154  Oid receiveOid = InvalidOid;
155  Oid sendOid = InvalidOid;
156  Oid typmodinOid = InvalidOid;
157  Oid typmodoutOid = InvalidOid;
158  Oid analyzeOid = InvalidOid;
159  char *array_type;
160  Oid array_oid;
161  Oid typoid;
162  Oid resulttype;
163  ListCell *pl;
164  ObjectAddress address;
165 
166  /*
167  * As of Postgres 8.4, we require superuser privilege to create a base
168  * type. This is simple paranoia: there are too many ways to mess up the
169  * system with an incorrect type definition (for instance, representation
170  * parameters that don't match what the C code expects). In practice it
171  * takes superuser privilege to create the I/O functions, and so the
172  * former requirement that you own the I/O functions pretty much forced
173  * superuserness anyway. We're just making doubly sure here.
174  *
175  * XXX re-enable NOT_USED code sections below if you remove this test.
176  */
177  if (!superuser())
178  ereport(ERROR,
179  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
180  errmsg("must be superuser to create a base type")));
181 
182  /* Convert list of names to a name and namespace */
183  typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
184 
185 #ifdef NOT_USED
186  /* XXX this is unnecessary given the superuser check above */
187  /* Check we have creation rights in target namespace */
188  aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
189  if (aclresult != ACLCHECK_OK)
190  aclcheck_error(aclresult, OBJECT_SCHEMA,
191  get_namespace_name(typeNamespace));
192 #endif
193 
194  /*
195  * Look to see if type already exists (presumably as a shell; if not,
196  * TypeCreate will complain).
197  */
198  typoid = GetSysCacheOid2(TYPENAMENSP,
199  CStringGetDatum(typeName),
200  ObjectIdGetDatum(typeNamespace));
201 
202  /*
203  * If it's not a shell, see if it's an autogenerated array type, and if so
204  * rename it out of the way.
205  */
206  if (OidIsValid(typoid) && get_typisdefined(typoid))
207  {
208  if (moveArrayTypeName(typoid, typeName, typeNamespace))
209  typoid = InvalidOid;
210  }
211 
212  /*
213  * If it doesn't exist, create it as a shell, so that the OID is known for
214  * use in the I/O function definitions.
215  */
216  if (!OidIsValid(typoid))
217  {
218  address = TypeShellMake(typeName, typeNamespace, GetUserId());
219  typoid = address.objectId;
220  /* Make new shell type visible for modification below */
222 
223  /*
224  * If the command was a parameterless CREATE TYPE, we're done ---
225  * creating the shell type was all we're supposed to do.
226  */
227  if (parameters == NIL)
228  return address;
229  }
230  else
231  {
232  /* Complain if dummy CREATE TYPE and entry already exists */
233  if (parameters == NIL)
234  ereport(ERROR,
236  errmsg("type \"%s\" already exists", typeName)));
237  }
238 
239  /* Extract the parameters from the parameter list */
240  foreach(pl, parameters)
241  {
242  DefElem *defel = (DefElem *) lfirst(pl);
243  DefElem **defelp;
244 
245  if (strcmp(defel->defname, "like") == 0)
246  defelp = &likeTypeEl;
247  else if (strcmp(defel->defname, "internallength") == 0)
248  defelp = &internalLengthEl;
249  else if (strcmp(defel->defname, "input") == 0)
250  defelp = &inputNameEl;
251  else if (strcmp(defel->defname, "output") == 0)
252  defelp = &outputNameEl;
253  else if (strcmp(defel->defname, "receive") == 0)
254  defelp = &receiveNameEl;
255  else if (strcmp(defel->defname, "send") == 0)
256  defelp = &sendNameEl;
257  else if (strcmp(defel->defname, "typmod_in") == 0)
258  defelp = &typmodinNameEl;
259  else if (strcmp(defel->defname, "typmod_out") == 0)
260  defelp = &typmodoutNameEl;
261  else if (strcmp(defel->defname, "analyze") == 0 ||
262  strcmp(defel->defname, "analyse") == 0)
263  defelp = &analyzeNameEl;
264  else if (strcmp(defel->defname, "category") == 0)
265  defelp = &categoryEl;
266  else if (strcmp(defel->defname, "preferred") == 0)
267  defelp = &preferredEl;
268  else if (strcmp(defel->defname, "delimiter") == 0)
269  defelp = &delimiterEl;
270  else if (strcmp(defel->defname, "element") == 0)
271  defelp = &elemTypeEl;
272  else if (strcmp(defel->defname, "default") == 0)
273  defelp = &defaultValueEl;
274  else if (strcmp(defel->defname, "passedbyvalue") == 0)
275  defelp = &byValueEl;
276  else if (strcmp(defel->defname, "alignment") == 0)
277  defelp = &alignmentEl;
278  else if (strcmp(defel->defname, "storage") == 0)
279  defelp = &storageEl;
280  else if (strcmp(defel->defname, "collatable") == 0)
281  defelp = &collatableEl;
282  else
283  {
284  /* WARNING, not ERROR, for historical backwards-compatibility */
286  (errcode(ERRCODE_SYNTAX_ERROR),
287  errmsg("type attribute \"%s\" not recognized",
288  defel->defname),
289  parser_errposition(pstate, defel->location)));
290  continue;
291  }
292  if (*defelp != NULL)
293  ereport(ERROR,
294  (errcode(ERRCODE_SYNTAX_ERROR),
295  errmsg("conflicting or redundant options"),
296  parser_errposition(pstate, defel->location)));
297  *defelp = defel;
298  }
299 
300  /*
301  * Now interpret the options; we do this separately so that LIKE can be
302  * overridden by other options regardless of the ordering in the parameter
303  * list.
304  */
305  if (likeTypeEl)
306  {
307  Type likeType;
308  Form_pg_type likeForm;
309 
310  likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
311  likeForm = (Form_pg_type) GETSTRUCT(likeType);
312  internalLength = likeForm->typlen;
313  byValue = likeForm->typbyval;
314  alignment = likeForm->typalign;
315  storage = likeForm->typstorage;
316  ReleaseSysCache(likeType);
317  }
318  if (internalLengthEl)
319  internalLength = defGetTypeLength(internalLengthEl);
320  if (inputNameEl)
321  inputName = defGetQualifiedName(inputNameEl);
322  if (outputNameEl)
323  outputName = defGetQualifiedName(outputNameEl);
324  if (receiveNameEl)
325  receiveName = defGetQualifiedName(receiveNameEl);
326  if (sendNameEl)
327  sendName = defGetQualifiedName(sendNameEl);
328  if (typmodinNameEl)
329  typmodinName = defGetQualifiedName(typmodinNameEl);
330  if (typmodoutNameEl)
331  typmodoutName = defGetQualifiedName(typmodoutNameEl);
332  if (analyzeNameEl)
333  analyzeName = defGetQualifiedName(analyzeNameEl);
334  if (categoryEl)
335  {
336  char *p = defGetString(categoryEl);
337 
338  category = p[0];
339  /* restrict to non-control ASCII */
340  if (category < 32 || category > 126)
341  ereport(ERROR,
342  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
343  errmsg("invalid type category \"%s\": must be simple ASCII",
344  p)));
345  }
346  if (preferredEl)
347  preferred = defGetBoolean(preferredEl);
348  if (delimiterEl)
349  {
350  char *p = defGetString(delimiterEl);
351 
352  delimiter = p[0];
353  /* XXX shouldn't we restrict the delimiter? */
354  }
355  if (elemTypeEl)
356  {
357  elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
358  /* disallow arrays of pseudotypes */
359  if (get_typtype(elemType) == TYPTYPE_PSEUDO)
360  ereport(ERROR,
361  (errcode(ERRCODE_DATATYPE_MISMATCH),
362  errmsg("array element type cannot be %s",
363  format_type_be(elemType))));
364  }
365  if (defaultValueEl)
366  defaultValue = defGetString(defaultValueEl);
367  if (byValueEl)
368  byValue = defGetBoolean(byValueEl);
369  if (alignmentEl)
370  {
371  char *a = defGetString(alignmentEl);
372 
373  /*
374  * Note: if argument was an unquoted identifier, parser will have
375  * applied translations to it, so be prepared to recognize translated
376  * type names as well as the nominal form.
377  */
378  if (pg_strcasecmp(a, "double") == 0 ||
379  pg_strcasecmp(a, "float8") == 0 ||
380  pg_strcasecmp(a, "pg_catalog.float8") == 0)
381  alignment = 'd';
382  else if (pg_strcasecmp(a, "int4") == 0 ||
383  pg_strcasecmp(a, "pg_catalog.int4") == 0)
384  alignment = 'i';
385  else if (pg_strcasecmp(a, "int2") == 0 ||
386  pg_strcasecmp(a, "pg_catalog.int2") == 0)
387  alignment = 's';
388  else if (pg_strcasecmp(a, "char") == 0 ||
389  pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
390  alignment = 'c';
391  else
392  ereport(ERROR,
393  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
394  errmsg("alignment \"%s\" not recognized", a)));
395  }
396  if (storageEl)
397  {
398  char *a = defGetString(storageEl);
399 
400  if (pg_strcasecmp(a, "plain") == 0)
401  storage = 'p';
402  else if (pg_strcasecmp(a, "external") == 0)
403  storage = 'e';
404  else if (pg_strcasecmp(a, "extended") == 0)
405  storage = 'x';
406  else if (pg_strcasecmp(a, "main") == 0)
407  storage = 'm';
408  else
409  ereport(ERROR,
410  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
411  errmsg("storage \"%s\" not recognized", a)));
412  }
413  if (collatableEl)
414  collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
415 
416  /*
417  * make sure we have our required definitions
418  */
419  if (inputName == NIL)
420  ereport(ERROR,
421  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
422  errmsg("type input function must be specified")));
423  if (outputName == NIL)
424  ereport(ERROR,
425  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
426  errmsg("type output function must be specified")));
427 
428  if (typmodinName == NIL && typmodoutName != NIL)
429  ereport(ERROR,
430  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
431  errmsg("type modifier output function is useless without a type modifier input function")));
432 
433  /*
434  * Convert I/O proc names to OIDs
435  */
436  inputOid = findTypeInputFunction(inputName, typoid);
437  outputOid = findTypeOutputFunction(outputName, typoid);
438  if (receiveName)
439  receiveOid = findTypeReceiveFunction(receiveName, typoid);
440  if (sendName)
441  sendOid = findTypeSendFunction(sendName, typoid);
442 
443  /*
444  * Verify that I/O procs return the expected thing. If we see OPAQUE,
445  * complain and change it to the correct type-safe choice.
446  */
447  resulttype = get_func_rettype(inputOid);
448  if (resulttype != typoid)
449  {
450  if (resulttype == OPAQUEOID)
451  {
452  /* backwards-compatibility hack */
454  (errmsg("changing return type of function %s from %s to %s",
455  NameListToString(inputName), "opaque", typeName)));
456  SetFunctionReturnType(inputOid, typoid);
457  }
458  else
459  ereport(ERROR,
460  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
461  errmsg("type input function %s must return type %s",
462  NameListToString(inputName), typeName)));
463  }
464  resulttype = get_func_rettype(outputOid);
465  if (resulttype != CSTRINGOID)
466  {
467  if (resulttype == OPAQUEOID)
468  {
469  /* backwards-compatibility hack */
471  (errmsg("changing return type of function %s from %s to %s",
472  NameListToString(outputName), "opaque", "cstring")));
473  SetFunctionReturnType(outputOid, CSTRINGOID);
474  }
475  else
476  ereport(ERROR,
477  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
478  errmsg("type output function %s must return type %s",
479  NameListToString(outputName), "cstring")));
480  }
481  if (receiveOid)
482  {
483  resulttype = get_func_rettype(receiveOid);
484  if (resulttype != typoid)
485  ereport(ERROR,
486  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
487  errmsg("type receive function %s must return type %s",
488  NameListToString(receiveName), typeName)));
489  }
490  if (sendOid)
491  {
492  resulttype = get_func_rettype(sendOid);
493  if (resulttype != BYTEAOID)
494  ereport(ERROR,
495  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
496  errmsg("type send function %s must return type %s",
497  NameListToString(sendName), "bytea")));
498  }
499 
500  /*
501  * Convert typmodin/out function proc names to OIDs.
502  */
503  if (typmodinName)
504  typmodinOid = findTypeTypmodinFunction(typmodinName);
505  if (typmodoutName)
506  typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
507 
508  /*
509  * Convert analysis function proc name to an OID. If no analysis function
510  * is specified, we'll use zero to select the built-in default algorithm.
511  */
512  if (analyzeName)
513  analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
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 #ifdef NOT_USED
524  /* XXX this is unnecessary given the superuser check above */
525  if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
527  NameListToString(inputName));
528  if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
530  NameListToString(outputName));
531  if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
533  NameListToString(receiveName));
534  if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
536  NameListToString(sendName));
537  if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
539  NameListToString(typmodinName));
540  if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
542  NameListToString(typmodoutName));
543  if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
545  NameListToString(analyzeName));
546 #endif
547 
548  /*
549  * Print warnings if any of the type's I/O functions are marked volatile.
550  * There is a general assumption that I/O functions are stable or
551  * immutable; this allows us for example to mark record_in/record_out
552  * stable rather than volatile. Ideally we would throw errors not just
553  * warnings here; but since this check is new as of 9.5, and since the
554  * volatility marking might be just an error-of-omission and not a true
555  * indication of how the function behaves, we'll let it pass as a warning
556  * for now.
557  */
558  if (inputOid && func_volatile(inputOid) == PROVOLATILE_VOLATILE)
560  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
561  errmsg("type input function %s should not be volatile",
562  NameListToString(inputName))));
563  if (outputOid && func_volatile(outputOid) == PROVOLATILE_VOLATILE)
565  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
566  errmsg("type output function %s should not be volatile",
567  NameListToString(outputName))));
568  if (receiveOid && func_volatile(receiveOid) == PROVOLATILE_VOLATILE)
570  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
571  errmsg("type receive function %s should not be volatile",
572  NameListToString(receiveName))));
573  if (sendOid && func_volatile(sendOid) == PROVOLATILE_VOLATILE)
575  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
576  errmsg("type send function %s should not be volatile",
577  NameListToString(sendName))));
578  if (typmodinOid && func_volatile(typmodinOid) == PROVOLATILE_VOLATILE)
580  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
581  errmsg("type modifier input function %s should not be volatile",
582  NameListToString(typmodinName))));
583  if (typmodoutOid && func_volatile(typmodoutOid) == PROVOLATILE_VOLATILE)
585  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
586  errmsg("type modifier output function %s should not be volatile",
587  NameListToString(typmodoutName))));
588 
589  /*
590  * OK, we're done checking, time to make the type. We must assign the
591  * array type OID ahead of calling TypeCreate, since the base type and
592  * array type each refer to the other.
593  */
594  array_oid = AssignTypeArrayOid();
595 
596  /*
597  * now have TypeCreate do all the real work.
598  *
599  * Note: the pg_type.oid is stored in user tables as array elements (base
600  * types) in ArrayType and in composite types in DatumTupleFields. This
601  * oid must be preserved by binary upgrades.
602  */
603  address =
604  TypeCreate(InvalidOid, /* no predetermined type OID */
605  typeName, /* type name */
606  typeNamespace, /* namespace */
607  InvalidOid, /* relation oid (n/a here) */
608  0, /* relation kind (ditto) */
609  GetUserId(), /* owner's ID */
610  internalLength, /* internal size */
611  TYPTYPE_BASE, /* type-type (base type) */
612  category, /* type-category */
613  preferred, /* is it a preferred type? */
614  delimiter, /* array element delimiter */
615  inputOid, /* input procedure */
616  outputOid, /* output procedure */
617  receiveOid, /* receive procedure */
618  sendOid, /* send procedure */
619  typmodinOid, /* typmodin procedure */
620  typmodoutOid, /* typmodout procedure */
621  analyzeOid, /* analyze procedure */
622  elemType, /* element type ID */
623  false, /* this is not an array type */
624  array_oid, /* array type we are about to create */
625  InvalidOid, /* base type ID (only for domains) */
626  defaultValue, /* default type value */
627  NULL, /* no binary form available */
628  byValue, /* passed by value */
629  alignment, /* required alignment */
630  storage, /* TOAST strategy */
631  -1, /* typMod (Domains only) */
632  0, /* Array Dimensions of typbasetype */
633  false, /* Type NOT NULL */
634  collation); /* type's collation */
635  Assert(typoid == address.objectId);
636 
637  /*
638  * Create the array type that goes with it.
639  */
640  array_type = makeArrayTypeName(typeName, typeNamespace);
641 
642  /* alignment must be 'i' or 'd' for arrays */
643  alignment = (alignment == 'd') ? 'd' : 'i';
644 
645  TypeCreate(array_oid, /* force assignment of this type OID */
646  array_type, /* type name */
647  typeNamespace, /* namespace */
648  InvalidOid, /* relation oid (n/a here) */
649  0, /* relation kind (ditto) */
650  GetUserId(), /* owner's ID */
651  -1, /* internal size (always varlena) */
652  TYPTYPE_BASE, /* type-type (base type) */
653  TYPCATEGORY_ARRAY, /* type-category (array) */
654  false, /* array types are never preferred */
655  delimiter, /* array element delimiter */
656  F_ARRAY_IN, /* input procedure */
657  F_ARRAY_OUT, /* output procedure */
658  F_ARRAY_RECV, /* receive procedure */
659  F_ARRAY_SEND, /* send procedure */
660  typmodinOid, /* typmodin procedure */
661  typmodoutOid, /* typmodout procedure */
662  F_ARRAY_TYPANALYZE, /* analyze procedure */
663  typoid, /* element type ID */
664  true, /* yes this is an array type */
665  InvalidOid, /* no further array type */
666  InvalidOid, /* base type ID */
667  NULL, /* never a default type value */
668  NULL, /* binary default isn't sent either */
669  false, /* never passed by value */
670  alignment, /* see above */
671  'x', /* ARRAY is always toastable */
672  -1, /* typMod (Domains only) */
673  0, /* Array dimensions of typbasetype */
674  false, /* Type NOT NULL */
675  collation); /* type's collation */
676 
677  pfree(array_type);
678 
679  return address;
680 }
signed short int16
Definition: c.h:312
#define NIL
Definition: pg_list.h:69
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:766
static Oid findTypeOutputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1773
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:247
static Oid findTypeReceiveFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1824
Oid GetUserId(void)
Definition: miscinit.c:379
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2975
static Oid findTypeTypmodinFunction(List *procname)
Definition: typecmds.c:1878
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:1927
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
char get_typtype(Oid typid)
Definition: lsyscache.c:2383
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
unsigned int Oid
Definition: postgres_ext.h:31
ObjectAddress TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
Definition: pg_type.c:55
#define OidIsValid(objectId)
Definition: c.h:605
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4686
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1444
#define GetSysCacheOid2(cacheId, key1, key2)
Definition: syscache.h:193
int defGetTypeLength(DefElem *def)
Definition: define.c:283
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
bool defGetBoolean(DefElem *def)
Definition: define.c:111
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:255
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
char * defGetString(DefElem *def)
Definition: define.c:49
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1932
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:832
int location
Definition: parsenodes.h:733
#define CStringGetDatum(X)
Definition: postgres.h:561
static Oid findTypeTypmodoutFunction(List *procname)
Definition: typecmds.c:1905
#define ereport(elevel, rest)
Definition: elog.h:122
#define WARNING
Definition: elog.h:40
char * NameListToString(List *names)
Definition: namespace.c:3082
void CommandCounterIncrement(void)
Definition: xact.c:914
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
void SetFunctionReturnType(Oid funcOid, Oid newRetType)
#define InvalidOid
Definition: postgres_ext.h:36
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
List * defGetQualifiedName(DefElem *def)
Definition: define.c:223
FormData_pg_type * Form_pg_type
Definition: pg_type.h:247
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2095
static Oid findTypeInputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1706
char func_volatile(Oid funcid)
Definition: lsyscache.c:1569
int errmsg(const char *fmt,...)
Definition: elog.c:797
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 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:194
char * defname
Definition: parsenodes.h:730
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
Definition: pg_list.h:45
bool pg_proc_ownercheck(Oid proc_oid, Oid roleid)
Definition: aclchk.c:4826
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274
static Oid findTypeSendFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1855

◆ domainAddConstraint()

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

Definition at line 3057 of file typecmds.c.

References assign_expr_collations(), ChooseConstraintName(), coerce_to_boolean(), CoerceToDomainValue::collation, Constraint::conname, CONSTRAINT_DOMAIN, ConstraintNameIsUsed(), contain_var_clause(), CreateConstraintEntry(), deparse_expression(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, EXPR_KIND_DOMAIN_CHECK, get_typcollation(), InvalidOid, list_length(), 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(), CoerceToDomainValue::typeId, and CoerceToDomainValue::typeMod.

Referenced by AlterDomainAddConstraint(), and DefineDomain().

3060 {
3061  Node *expr;
3062  char *ccsrc;
3063  char *ccbin;
3064  ParseState *pstate;
3065  CoerceToDomainValue *domVal;
3066  Oid ccoid;
3067 
3068  /*
3069  * Assign or validate constraint name
3070  */
3071  if (constr->conname)
3072  {
3074  domainOid,
3075  domainNamespace,
3076  constr->conname))
3077  ereport(ERROR,
3079  errmsg("constraint \"%s\" for domain \"%s\" already exists",
3080  constr->conname, domainName)));
3081  }
3082  else
3083  constr->conname = ChooseConstraintName(domainName,
3084  NULL,
3085  "check",
3086  domainNamespace,
3087  NIL);
3088 
3089  /*
3090  * Convert the A_EXPR in raw_expr into an EXPR
3091  */
3092  pstate = make_parsestate(NULL);
3093 
3094  /*
3095  * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
3096  * the expression. Note that it will appear to have the type of the base
3097  * type, not the domain. This seems correct since within the check
3098  * expression, we should not assume the input value can be considered a
3099  * member of the domain.
3100  */
3101  domVal = makeNode(CoerceToDomainValue);
3102  domVal->typeId = baseTypeOid;
3103  domVal->typeMod = typMod;
3104  domVal->collation = get_typcollation(baseTypeOid);
3105  domVal->location = -1; /* will be set when/if used */
3106 
3108  pstate->p_ref_hook_state = (void *) domVal;
3109 
3110  expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
3111 
3112  /*
3113  * Make sure it yields a boolean result.
3114  */
3115  expr = coerce_to_boolean(pstate, expr, "CHECK");
3116 
3117  /*
3118  * Fix up collation information.
3119  */
3120  assign_expr_collations(pstate, expr);
3121 
3122  /*
3123  * Domains don't allow variables (this is probably dead code now that
3124  * add_missing_from is history, but let's be sure).
3125  */
3126  if (list_length(pstate->p_rtable) != 0 ||
3127  contain_var_clause(expr))
3128  ereport(ERROR,
3129  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3130  errmsg("cannot use table references in domain check constraint")));
3131 
3132  /*
3133  * Convert to string form for storage.
3134  */
3135  ccbin = nodeToString(expr);
3136 
3137  /*
3138  * Deparse it to produce text for consrc.
3139  */
3140  ccsrc = deparse_expression(expr,
3141  NIL, false, false);
3142 
3143  /*
3144  * Store the constraint in pg_constraint
3145  */
3146  ccoid =
3147  CreateConstraintEntry(constr->conname, /* Constraint Name */
3148  domainNamespace, /* namespace */
3149  CONSTRAINT_CHECK, /* Constraint Type */
3150  false, /* Is Deferrable */
3151  false, /* Is Deferred */
3152  !constr->skip_validation, /* Is Validated */
3153  InvalidOid, /* no parent constraint */
3154  InvalidOid, /* not a relation constraint */
3155  NULL,
3156  0,
3157  0,
3158  domainOid, /* domain constraint */
3159  InvalidOid, /* no associated index */
3160  InvalidOid, /* Foreign key fields */
3161  NULL,
3162  NULL,
3163  NULL,
3164  NULL,
3165  0,
3166  ' ',
3167  ' ',
3168  ' ',
3169  NULL, /* not an exclusion constraint */
3170  expr, /* Tree form of check constraint */
3171  ccbin, /* Binary form of check constraint */
3172  ccsrc, /* Source form of check constraint */
3173  true, /* is local */
3174  0, /* inhcount */
3175  false, /* connoinherit */
3176  false); /* is_internal */
3177  if (constrAddr)
3178  ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
3179 
3180  /*
3181  * Return the compiled constraint expression so the calling routine can
3182  * perform any additional required tests.
3183  */
3184  return ccbin;
3185 }
#define NIL
Definition: pg_list.h:69
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
static Node * replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref)
Definition: typecmds.c:3189
Node * raw_expr
Definition: parsenodes.h:2102
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:146
Definition: nodes.h:517
int errcode(int sqlerrcode)
Definition: elog.c:575
bool contain_var_clause(Node *node)
Definition: var.c:331
char * conname
Definition: parsenodes.h:2095
unsigned int Oid
Definition: postgres_ext.h:31
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
void assign_expr_collations(ParseState *pstate, Node *expr)
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvalidOid
Definition: postgres_ext.h:36
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:2799
#define makeNode(_type_)
Definition: nodes.h:565
void * p_ref_hook_state
Definition: parse_node.h:216
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3071
static int list_length(const List *l)
Definition: pg_list.h:89
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, Oid objNamespace, const char *conname)
int errmsg(const char *fmt,...)
Definition: elog.c:797
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, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, const char *conSrc, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:51
char * nodeToString(const void *obj)
Definition: outfuncs.c:4331
PreParseColumnRefHook p_pre_columnref_hook
Definition: parse_node.h:212
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
bool skip_validation
Definition: parsenodes.h:2135
List * p_rtable
Definition: parse_node.h:174
Node * coerce_to_boolean(ParseState *pstate, Node *node, const char *constructName)

◆ findRangeCanonicalFunction()

static Oid findRangeCanonicalFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 2006 of file typecmds.c.

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_FUNCTION, OidIsValid, and pg_proc_aclcheck().

Referenced by DefineRange().

2007 {
2008  Oid argList[1];
2009  Oid procOid;
2010  AclResult aclresult;
2011 
2012  /*
2013  * Range canonical functions must take and return the range type, and must
2014  * be immutable.
2015  */
2016  argList[0] = typeOid;
2017 
2018  procOid = LookupFuncName(procname, 1, argList, true);
2019 
2020  if (!OidIsValid(procOid))
2021  ereport(ERROR,
2022  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2023  errmsg("function %s does not exist",
2024  func_signature_string(procname, 1, NIL, argList))));
2025 
2026  if (get_func_rettype(procOid) != typeOid)
2027  ereport(ERROR,
2028  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2029  errmsg("range canonical function %s must return range type",
2030  func_signature_string(procname, 1, NIL, argList))));
2031 
2032  if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2033  ereport(ERROR,
2034  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2035  errmsg("range canonical function %s must be immutable",
2036  func_signature_string(procname, 1, NIL, argList))));
2037 
2038  /* Also, range type's creator must have permission to call function */
2039  aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
2040  if (aclresult != ACLCHECK_OK)
2041  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
2042 
2043  return procOid;
2044 }
#define NIL
Definition: pg_list.h:69
Oid GetUserId(void)
Definition: miscinit.c:379
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1444
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1397
#define ereport(elevel, rest)
Definition: elog.h:122
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1953
AclResult
Definition: acl.h:178
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1974
char func_volatile(Oid funcid)
Definition: lsyscache.c:1569
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ACL_EXECUTE
Definition: parsenodes.h:81
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4648

◆ findRangeSubOpclass()

static Oid findRangeSubOpclass ( List opcname,
Oid  subtype 
)
static

Definition at line 1967 of file typecmds.c.

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

1968 {
1969  Oid opcid;
1970  Oid opInputType;
1971 
1972  if (opcname != NIL)
1973  {
1974  opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
1975 
1976  /*
1977  * Verify that the operator class accepts this datatype. Note we will
1978  * accept binary compatibility.
1979  */
1980  opInputType = get_opclass_input_type(opcid);
1981  if (!IsBinaryCoercible(subtype, opInputType))
1982  ereport(ERROR,
1983  (errcode(ERRCODE_DATATYPE_MISMATCH),
1984  errmsg("operator class \"%s\" does not accept data type %s",
1985  NameListToString(opcname),
1986  format_type_be(subtype))));
1987  }
1988  else
1989  {
1990  opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
1991  if (!OidIsValid(opcid))
1992  {
1993  /* We spell the error message identically to ResolveOpClass */
1994  ereport(ERROR,
1995  (errcode(ERRCODE_UNDEFINED_OBJECT),
1996  errmsg("data type %s has no default operator class for access method \"%s\"",
1997  format_type_be(subtype), "btree"),
1998  errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
1999  }
2000  }
2001 
2002  return opcid;
2003 }
#define NIL
Definition: pg_list.h:69
int errhint(const char *fmt,...)
Definition: elog.c:987
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:1797
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
Definition: opclasscmds.c:221
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
bool IsBinaryCoercible(Oid srctype, Oid targettype)
char * NameListToString(List *names)
Definition: namespace.c:3082
int errmsg(const char *fmt,...)
Definition: elog.c:797
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1054

◆ findRangeSubtypeDiffFunction()

static Oid findRangeSubtypeDiffFunction ( List procname,
Oid  subtype 
)
static

Definition at line 2047 of file typecmds.c.

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_FUNCTION, OidIsValid, and pg_proc_aclcheck().

Referenced by DefineRange().

2048 {
2049  Oid argList[2];
2050  Oid procOid;
2051  AclResult aclresult;
2052 
2053  /*
2054  * Range subtype diff functions must take two arguments of the subtype,
2055  * must return float8, and must be immutable.
2056  */
2057  argList[0] = subtype;
2058  argList[1] = subtype;
2059 
2060  procOid = LookupFuncName(procname, 2, argList, true);
2061 
2062  if (!OidIsValid(procOid))
2063  ereport(ERROR,
2064  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2065  errmsg("function %s does not exist",
2066  func_signature_string(procname, 2, NIL, argList))));
2067 
2068  if (get_func_rettype(procOid) != FLOAT8OID)
2069  ereport(ERROR,
2070  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2071  errmsg("range subtype diff function %s must return type %s",
2072  func_signature_string(procname, 2, NIL, argList),
2073  "double precision")));
2074 
2075  if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2076  ereport(ERROR,
2077  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2078  errmsg("range subtype diff function %s must be immutable",
2079  func_signature_string(procname, 2, NIL, argList))));
2080 
2081  /* Also, range type's creator must have permission to call function */
2082  aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
2083  if (aclresult != ACLCHECK_OK)
2084  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
2085 
2086  return procOid;
2087 }
#define NIL
Definition: pg_list.h:69
Oid GetUserId(void)
Definition: miscinit.c:379
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1444
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3348
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1397
#define ereport(elevel, rest)
Definition: elog.h:122
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1953
AclResult
Definition: acl.h:178
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1974
char func_volatile(Oid funcid)
Definition: lsyscache.c:1569
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ACL_EXECUTE
Definition: parsenodes.h:81
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4648

◆ findTypeAnalyzeFunction()

static Oid findTypeAnalyzeFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 1932 of file typecmds.c.

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

Referenced by DefineType().

1933 {
1934  Oid argList[1];
1935  Oid procOid;
1936 
1937  /*
1938  * Analyze functions always take one INTERNAL argument and return bool.
1939  */
1940  argList[0] = INTERNALOID;
1941 
1942  procOid = LookupFuncName(procname, 1, argList, true);
1943  if (!OidIsValid(procOid))
1944  ereport(ERROR,
1945  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1946  errmsg("function %s does not exist",
1947  func_signature_string(procname, 1, NIL, argList))));
1948 
1949  if (get_func_rettype(procOid) != BOOLOID)
1950  ereport(ERROR,
1951  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1952  errmsg("type analyze function %s must return type %s",
1953  NameListToString(procname), "boolean")));
1954 
1955  return procOid;
1956 }
#define NIL
Definition: pg_list.h:69
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1444
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1953
char * NameListToString(List *names)
Definition: namespace.c:3082
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1974
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ findTypeInputFunction()

static Oid findTypeInputFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 1706 of file typecmds.c.

References CommandCounterIncrement(), ereport, errcode(), errmsg(), ERROR, func_signature_string(), InvalidOid, LookupFuncName(), NameListToString(), NIL, OidIsValid, SetFunctionArgType(), and WARNING.

Referenced by DefineType().

1707 {
1708  Oid argList[3];
1709  Oid procOid;
1710 
1711  /*
1712  * Input functions can take a single argument of type CSTRING, or three
1713  * arguments (string, typioparam OID, typmod).
1714  *
1715  * For backwards compatibility we allow OPAQUE in place of CSTRING; if we
1716  * see this, we issue a warning and fix up the pg_proc entry.
1717  */
1718  argList[0] = CSTRINGOID;
1719 
1720  procOid = LookupFuncName(procname, 1, argList, true);
1721  if (OidIsValid(procOid))
1722  return procOid;
1723 
1724  argList[1] = OIDOID;
1725  argList[2] = INT4OID;
1726 
1727  procOid = LookupFuncName(procname, 3, argList, true);
1728  if (OidIsValid(procOid))
1729  return procOid;
1730 
1731  /* No luck, try it with OPAQUE */
1732  argList[0] = OPAQUEOID;
1733 
1734  procOid = LookupFuncName(procname, 1, argList, true);
1735 
1736  if (!OidIsValid(procOid))
1737  {
1738  argList[1] = OIDOID;
1739  argList[2] = INT4OID;
1740 
1741  procOid = LookupFuncName(procname, 3, argList, true);
1742  }
1743 
1744  if (OidIsValid(procOid))
1745  {
1746  /* Found, but must complain and fix the pg_proc entry */
1747  ereport(WARNING,
1748  (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"",
1749  NameListToString(procname))));
1750  SetFunctionArgType(procOid, 0, CSTRINGOID);
1751 
1752  /*
1753  * Need CommandCounterIncrement since DefineType will likely try to
1754  * alter the pg_proc tuple again.
1755  */
1757 
1758  return procOid;
1759  }
1760 
1761  /* Use CSTRING (preferred) in the error message */
1762  argList[0] = CSTRINGOID;
1763 
1764  ereport(ERROR,
1765  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1766  errmsg("function %s does not exist",
1767  func_signature_string(procname, 1, NIL, argList))));
1768 
1769  return InvalidOid; /* keep compiler quiet */
1770 }
#define NIL
Definition: pg_list.h:69
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
#define ERROR
Definition: elog.h:43
void SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType)
#define ereport(elevel, rest)
Definition: elog.h:122
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1953
#define WARNING
Definition: elog.h:40
char * NameListToString(List *names)
Definition: namespace.c:3082
void CommandCounterIncrement(void)
Definition: xact.c:914
#define InvalidOid
Definition: postgres_ext.h:36
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1974
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ findTypeOutputFunction()

static Oid findTypeOutputFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 1773 of file typecmds.c.

References CommandCounterIncrement(), ereport, errcode(), errmsg(), ERROR, format_type_be(), func_signature_string(), InvalidOid, LookupFuncName(), NameListToString(), NIL, OidIsValid, SetFunctionArgType(), and WARNING.

Referenced by DefineType().

1774 {
1775  Oid argList[1];
1776  Oid procOid;
1777 
1778  /*
1779  * Output functions can take a single argument of the type.
1780  *
1781  * For backwards compatibility we allow OPAQUE in place of the actual type
1782  * name; if we see this, we issue a warning and fix up the pg_proc entry.
1783  */
1784  argList[0] = typeOid;
1785 
1786  procOid = LookupFuncName(procname, 1, argList, true);
1787  if (OidIsValid(procOid))
1788  return procOid;
1789 
1790  /* No luck, try it with OPAQUE */
1791  argList[0] = OPAQUEOID;
1792 
1793  procOid = LookupFuncName(procname, 1, argList, true);
1794 
1795  if (OidIsValid(procOid))
1796  {
1797  /* Found, but must complain and fix the pg_proc entry */
1798  ereport(WARNING,
1799  (errmsg("changing argument type of function %s from \"opaque\" to %s",
1800  NameListToString(procname), format_type_be(typeOid))));
1801  SetFunctionArgType(procOid, 0, typeOid);
1802 
1803  /*
1804  * Need CommandCounterIncrement since DefineType will likely try to
1805  * alter the pg_proc tuple again.
1806  */
1808 
1809  return procOid;
1810  }
1811 
1812  /* Use type name, not OPAQUE, in the failure message. */
1813  argList[0] = typeOid;
1814 
1815  ereport(ERROR,
1816  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1817  errmsg("function %s does not exist",
1818  func_signature_string(procname, 1, NIL, argList))));
1819 
1820  return InvalidOid; /* keep compiler quiet */
1821 }
#define NIL
Definition: pg_list.h:69
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
#define ERROR
Definition: elog.h:43
void SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType)
#define ereport(elevel, rest)
Definition: elog.h:122
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1953
#define WARNING
Definition: elog.h:40
char * NameListToString(List *names)
Definition: namespace.c:3082
void CommandCounterIncrement(void)
Definition: xact.c:914
#define InvalidOid
Definition: postgres_ext.h:36
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1974
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ findTypeReceiveFunction()

static Oid findTypeReceiveFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 1824 of file typecmds.c.

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

Referenced by DefineType().

1825 {
1826  Oid argList[3];
1827  Oid procOid;
1828 
1829  /*
1830  * Receive functions can take a single argument of type INTERNAL, or three
1831  * arguments (internal, typioparam OID, typmod).
1832  */
1833  argList[0] = INTERNALOID;
1834 
1835  procOid = LookupFuncName(procname, 1, argList, true);
1836  if (OidIsValid(procOid))
1837  return procOid;
1838 
1839  argList[1] = OIDOID;
1840  argList[2] = INT4OID;
1841 
1842  procOid = LookupFuncName(procname, 3, argList, true);
1843  if (OidIsValid(procOid))
1844  return procOid;
1845 
1846  ereport(ERROR,
1847  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1848  errmsg("function %s does not exist",
1849  func_signature_string(procname, 1, NIL, argList))));
1850 
1851  return InvalidOid; /* keep compiler quiet */
1852 }
#define NIL
Definition: pg_list.h:69
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1953
#define InvalidOid
Definition: postgres_ext.h:36
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1974
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ findTypeSendFunction()

static Oid findTypeSendFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 1855 of file typecmds.c.

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

Referenced by DefineType().

1856 {
1857  Oid argList[1];
1858  Oid procOid;
1859 
1860  /*
1861  * Send functions can take a single argument of the type.
1862  */
1863  argList[0] = typeOid;
1864 
1865  procOid = LookupFuncName(procname, 1, argList, true);
1866  if (OidIsValid(procOid))
1867  return procOid;
1868 
1869  ereport(ERROR,
1870  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1871  errmsg("function %s does not exist",
1872  func_signature_string(procname, 1, NIL, argList))));
1873 
1874  return InvalidOid; /* keep compiler quiet */
1875 }
#define NIL
Definition: pg_list.h:69
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1953
#define InvalidOid
Definition: postgres_ext.h:36
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1974
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ findTypeTypmodinFunction()

static Oid findTypeTypmodinFunction ( List procname)
static

Definition at line 1878 of file typecmds.c.

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

Referenced by DefineType().

1879 {
1880  Oid argList[1];
1881  Oid procOid;
1882 
1883  /*
1884  * typmodin functions always take one cstring[] argument and return int4.
1885  */
1886  argList[0] = CSTRINGARRAYOID;
1887 
1888  procOid = LookupFuncName(procname, 1, argList, true);
1889  if (!OidIsValid(procOid))
1890  ereport(ERROR,
1891  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1892  errmsg("function %s does not exist",
1893  func_signature_string(procname, 1, NIL, argList))));
1894 
1895  if (get_func_rettype(procOid) != INT4OID)
1896  ereport(ERROR,
1897  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1898  errmsg("typmod_in function %s must return type %s",
1899  NameListToString(procname), "integer")));
1900 
1901  return procOid;
1902 }
#define NIL
Definition: pg_list.h:69
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1444
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1953
char * NameListToString(List *names)
Definition: namespace.c:3082
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1974
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ findTypeTypmodoutFunction()

static Oid findTypeTypmodoutFunction ( List procname)
static

Definition at line 1905 of file typecmds.c.

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

Referenced by DefineType().

1906 {
1907  Oid argList[1];
1908  Oid procOid;
1909 
1910  /*
1911  * typmodout functions always take one int4 argument and return cstring.
1912  */
1913  argList[0] = INT4OID;
1914 
1915  procOid = LookupFuncName(procname, 1, argList, true);
1916  if (!OidIsValid(procOid))
1917  ereport(ERROR,
1918  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1919  errmsg("function %s does not exist",
1920  func_signature_string(procname, 1, NIL, argList))));
1921 
1922  if (get_func_rettype(procOid) != CSTRINGOID)
1923  ereport(ERROR,
1924  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1925  errmsg("typmod_out function %s must return type %s",
1926  NameListToString(procname), "cstring")));
1927 
1928  return procOid;
1929 }
#define NIL
Definition: pg_list.h:69
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1444
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:1953
char * NameListToString(List *names)
Definition: namespace.c:3082
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1974
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ get_rels_with_domain()

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

Definition at line 2868 of file typecmds.c.

References AccessShareLock, Assert, RelToCheck::atts, BTEqualStrategyNumber, check_stack_depth(), DependReferenceIndexId, find_composite_type_dependencies(), format_type_be(), get_typtype(), GETSTRUCT, heap_open(), HeapTupleIsValid, lcons(), 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(), and TupleDescAttr.

Referenced by AlterDomainNotNull(), and validateDomainConstraint().

2869 {
2870  List *result = NIL;
2871  char *domainTypeName = format_type_be(domainOid);
2872  Relation depRel;
2873  ScanKeyData key[2];
2874  SysScanDesc depScan;
2875  HeapTuple depTup;
2876 
2877  Assert(lockmode != NoLock);
2878 
2879  /* since this function recurses, it could be driven to stack overflow */
2881 
2882  /*
2883  * We scan pg_depend to find those things that depend on the domain. (We
2884  * assume we can ignore refobjsubid for a domain.)
2885  */
2886  depRel = heap_open(DependRelationId, AccessShareLock);
2887 
2888  ScanKeyInit(&key[0],
2889  Anum_pg_depend_refclassid,
2890  BTEqualStrategyNumber, F_OIDEQ,
2891  ObjectIdGetDatum(TypeRelationId));
2892  ScanKeyInit(&key[1],
2893  Anum_pg_depend_refobjid,
2894  BTEqualStrategyNumber, F_OIDEQ,
2895  ObjectIdGetDatum(domainOid));
2896 
2897  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2898  NULL, 2, key);
2899 
2900  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2901  {
2902  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2903  RelToCheck *rtc = NULL;
2904  ListCell *rellist;
2905  Form_pg_attribute pg_att;
2906  int ptr;
2907 
2908  /* Check for directly dependent types */
2909  if (pg_depend->classid == TypeRelationId)
2910  {
2911  if (get_typtype(pg_depend->objid) == TYPTYPE_DOMAIN)
2912  {
2913  /*
2914  * This is a sub-domain, so recursively add dependent columns
2915  * to the output list. This is a bit inefficient since we may
2916  * fail to combine RelToCheck entries when attributes of the
2917  * same rel have different derived domain types, but it's
2918  * probably not worth improving.
2919  */
2920  result = list_concat(result,
2921  get_rels_with_domain(pg_depend->objid,
2922  lockmode));
2923  }
2924  else
2925  {
2926  /*
2927  * Otherwise, it is some container type using the domain, so
2928  * fail if there are any columns of this type.
2929  */
2930  find_composite_type_dependencies(pg_depend->objid,
2931  NULL,
2932  domainTypeName);
2933  }
2934  continue;
2935  }
2936 
2937  /* Else, ignore dependees that aren't user columns of relations */
2938  /* (we assume system columns are never of domain types) */
2939  if (pg_depend->classid != RelationRelationId ||
2940  pg_depend->objsubid <= 0)
2941  continue;
2942 
2943  /* See if we already have an entry for this relation */
2944  foreach(rellist, result)
2945  {
2946  RelToCheck *rt = (RelToCheck *) lfirst(rellist);
2947 
2948  if (RelationGetRelid(rt->rel) == pg_depend->objid)
2949  {
2950  rtc = rt;
2951  break;
2952  }
2953  }
2954 
2955  if (rtc == NULL)
2956  {
2957  /* First attribute found for this relation */
2958  Relation rel;
2959 
2960  /* Acquire requested lock on relation */
2961  rel = relation_open(pg_depend->objid, lockmode);
2962 
2963  /*
2964  * Check to see if rowtype is stored anyplace as a composite-type
2965  * column; if so we have to fail, for now anyway.
2966  */
2967  if (OidIsValid(rel->rd_rel->reltype))
2969  NULL,
2970  domainTypeName);
2971 
2972  /*
2973  * Otherwise, we can ignore relations except those with both
2974  * storage and user-chosen column types.
2975  *
2976  * XXX If an index-only scan could satisfy "col::some_domain" from
2977  * a suitable expression index, this should also check expression
2978  * index columns.
2979  */
2980  if (rel->rd_rel->relkind != RELKIND_RELATION &&
2981  rel->rd_rel->relkind != RELKIND_MATVIEW)
2982  {
2983  relation_close(rel, lockmode);
2984  continue;
2985  }
2986 
2987  /* Build the RelToCheck entry with enough space for all atts */
2988  rtc = (RelToCheck *) palloc(sizeof(RelToCheck));
2989  rtc->rel = rel;
2990  rtc->natts = 0;
2991  rtc->atts = (int *) palloc(sizeof(int) * RelationGetNumberOfAttributes(rel));
2992  result = lcons(rtc, result);
2993  }
2994 
2995  /*
2996  * Confirm column has not been dropped, and is of the expected type.
2997  * This defends against an ALTER DROP COLUMN occurring just before we
2998  * acquired lock ... but if the whole table were dropped, we'd still
2999  * have a problem.
3000  */
3001  if (pg_depend->objsubid > RelationGetNumberOfAttributes(rtc->rel))
3002  continue;
3003  pg_att = TupleDescAttr(rtc->rel->rd_att, pg_depend->objsubid - 1);
3004  if (pg_att->attisdropped || pg_att->atttypid != domainOid)
3005  continue;
3006 
3007  /*
3008  * Okay, add column to result. We store the columns in column-number
3009  * order; this is just a hack to improve predictability of regression
3010  * test output ...
3011  */
3013 
3014  ptr = rtc->natts++;
3015  while (ptr > 0 && rtc->atts[ptr - 1] > pg_depend->objsubid)
3016  {
3017  rtc->atts[ptr] = rtc->atts[ptr - 1];
3018  ptr--;
3019  }
3020  rtc->atts[ptr] = pg_depend->objsubid;
3021  }
3022 
3023  systable_endscan(depScan);
3024 
3026 
3027  return result;
3028 }
#define NIL
Definition: pg_list.h:69
int * atts
Definition: typecmds.c:78
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:502
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
Relation rel
Definition: typecmds.c:76
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:413
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
#define DependReferenceIndexId
Definition: indexing.h:148
void find_composite_type_dependencies(Oid typeOid, Relation origRelation, const char *origTypeName)
Definition: tablecmds.c:5108
#define AccessShareLock
Definition: lockdefs.h:36
char get_typtype(Oid typid)
Definition: lsyscache.c:2383
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1270
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
List * list_concat(List *list1, List *list2)
Definition: list.c:321
Form_pg_class rd_rel
Definition: rel.h:84
#define OidIsValid(objectId)
Definition: c.h:605
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:331
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:419
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define NoLock
Definition: lockdefs.h:34
void check_stack_depth(void)
Definition: postgres.c:3155
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:71
static List * get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
Definition: typecmds.c:2868
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
TupleDesc rd_att
Definition: rel.h:85
List * lcons(void *datum, List *list)
Definition: list.c:259
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
void * palloc(Size size)
Definition: mcxt.c:924
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1124
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407
#define BTEqualStrategyNumber
Definition: stratnum.h:31
int natts
Definition: typecmds.c:77

◆ makeRangeConstructors()

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

Definition at line 1635 of file typecmds.c.

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

Referenced by DefineRange().

1637 {
1638  static const char *const prosrc[2] = {"range_constructor2",
1639  "range_constructor3"};
1640  static const int pronargs[2] = {2, 3};
1641 
1642  Oid constructorArgTypes[3];
1643  ObjectAddress myself,
1644  referenced;
1645  int i;
1646 
1647  constructorArgTypes[0] = subtype;
1648  constructorArgTypes[1] = subtype;
1649  constructorArgTypes[2] = TEXTOID;
1650 
1651  referenced.classId = TypeRelationId;
1652  referenced.objectId = rangeOid;
1653  referenced.objectSubId = 0;
1654 
1655  for (i = 0; i < lengthof(prosrc); i++)
1656  {
1657  oidvector *constructorArgTypesVector;
1658 
1659  constructorArgTypesVector = buildoidvector(constructorArgTypes,
1660  pronargs[i]);
1661 
1662  myself = ProcedureCreate(name, /* name: same as range type */
1663  namespace, /* namespace */
1664  false, /* replace */
1665  false, /* returns set */
1666  rangeOid, /* return type */
1667  BOOTSTRAP_SUPERUSERID, /* proowner */
1668  INTERNALlanguageId, /* language */
1669  F_FMGR_INTERNAL_VALIDATOR, /* language validator */
1670  prosrc[i], /* prosrc */
1671  NULL, /* probin */
1672  PROKIND_FUNCTION,
1673  false, /* security_definer */
1674  false, /* leakproof */
1675  false, /* isStrict */
1676  PROVOLATILE_IMMUTABLE, /* volatility */
1677  PROPARALLEL_SAFE, /* parallel safety */
1678  constructorArgTypesVector, /* parameterTypes */
1679  PointerGetDatum(NULL), /* allParameterTypes */
1680  PointerGetDatum(NULL), /* parameterModes */
1681  PointerGetDatum(NULL), /* parameterNames */
1682  NIL, /* parameterDefaults */
1683  PointerGetDatum(NULL), /* trftypes */
1684  PointerGetDatum(NULL), /* proconfig */
1685  1.0, /* procost */
1686  0.0); /* prorows */
1687 
1688  /*
1689  * Make the constructors internally-dependent on the range type so
1690  * that they go away silently when the type is dropped. Note that
1691  * pg_dump depends on this choice to avoid dumping the constructors.
1692  */
1693  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1694  }
1695 }
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, 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, float4 procost, float4 prorows)
Definition: pg_proc.c:66
#define NIL
Definition: pg_list.h:69
Definition: c.h:555
#define PointerGetDatum(X)
Definition: postgres.h:539
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
#define lengthof(array)
Definition: c.h:629
int16 pronargs
Definition: pg_proc.h:80
unsigned int Oid
Definition: postgres_ext.h:31
oidvector * buildoidvector(const Oid *oids, int n)
Definition: oid.c:167
const char * name
Definition: encode.c:521
int i

◆ RemoveTypeById()

void RemoveTypeById ( Oid  typeOid)

Definition at line 686 of file typecmds.c.

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

Referenced by doDeletion().

687 {
688  Relation relation;
689  HeapTuple tup;
690 
691  relation = heap_open(TypeRelationId, RowExclusiveLock);
692 
693  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
694  if (!HeapTupleIsValid(tup))
695  elog(ERROR, "cache lookup failed for type %u", typeOid);
696 
697  CatalogTupleDelete(relation, &tup->t_self);
698 
699  /*
700  * If it is an enum, delete the pg_enum entries too; we don't bother with
701  * making dependency entries for those, so it has to be done "by hand"
702  * here.
703  */
704  if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
705  EnumValuesDelete(typeOid);
706 
707  /*
708  * If it is a range type, delete the pg_range entry too; we don't bother
709  * with making a dependency entry for that, so it has to be done "by hand"
710  * here.
711  */