PostgreSQL Source Code  git master
typecmds.h File Reference
#include "access/htup.h"
#include "catalog/dependency.h"
#include "nodes/parsenodes.h"
Include dependency graph for typecmds.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define DEFAULT_TYPDELIM   ','
 

Functions

ObjectAddress DefineType (ParseState *pstate, List *names, List *parameters)
 
void RemoveTypeById (Oid typeOid)
 
ObjectAddress DefineDomain (CreateDomainStmt *stmt)
 
ObjectAddress DefineEnum (CreateEnumStmt *stmt)
 
ObjectAddress DefineRange (CreateRangeStmt *stmt)
 
ObjectAddress AlterEnum (AlterEnumStmt *stmt, bool isTopLevel)
 
ObjectAddress DefineCompositeType (RangeVar *typevar, List *coldeflist)
 
Oid AssignTypeArrayOid (void)
 
ObjectAddress AlterDomainDefault (List *names, Node *defaultRaw)
 
ObjectAddress AlterDomainNotNull (List *names, bool notNull)
 
ObjectAddress AlterDomainAddConstraint (List *names, Node *constr, ObjectAddress *constrAddr)
 
ObjectAddress AlterDomainValidateConstraint (List *names, const char *constrName)
 
ObjectAddress AlterDomainDropConstraint (List *names, const char *constrName, DropBehavior behavior, bool missing_ok)
 
void checkDomainOwner (HeapTuple tup)
 
ObjectAddress RenameType (RenameStmt *stmt)
 
ObjectAddress AlterTypeOwner (List *names, Oid newOwnerId, ObjectType objecttype)
 
void AlterTypeOwner_oid (Oid typeOid, Oid newOwnerId, bool hasDependEntry)
 
void AlterTypeOwnerInternal (Oid typeOid, Oid newOwnerId)
 
ObjectAddress AlterTypeNamespace (List *names, const char *newschema, ObjectType objecttype, Oid *oldschema)
 
Oid AlterTypeNamespace_oid (Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
 
Oid AlterTypeNamespaceInternal (Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
 

Macro Definition Documentation

◆ DEFAULT_TYPDELIM

#define DEFAULT_TYPDELIM   ','

Function Documentation

◆ AlterDomainAddConstraint()

ObjectAddress AlterDomainAddConstraint ( List names,
Node constr,
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:668
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:492
#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:668
#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:492
#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:367
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:668
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:492
#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:707
#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:668
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:492
#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:5210
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:668
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:492
#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:367
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:707
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:208
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:492
#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:312
#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:4777
#define OidIsValid(objectId)
Definition: c.h:605
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3662
#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:580
int errhint(const char *fmt,...)
Definition: elog.c:987
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
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:492
#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:12962
#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:668
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:4777
#define OidIsValid(objectId)
Definition: c.h:605
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4689
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3662
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3349
#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:707
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:668
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:492
#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:10242
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:668
#define RelationGetDescr(relation)
Definition: rel.h:433
#define DatumGetAclP(X)
Definition: acl.h:121
#define PointerGetDatum(X)
Definition: postgres.h:541
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:492
#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:781
uintptr_t Datum
Definition: postgres.h:367
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:109
#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:668
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:4777
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3662
#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:707

◆ 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:492
#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:563
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:668
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:4689
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3662
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:3349
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:492
#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:563
#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:367
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:707
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4739
#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:4689
#define GetSysCacheOid2(cacheId, key1, key2)
Definition: syscache.h:193
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3349
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#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:563
#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:4689
#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:3349
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:255
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#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:563
#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:668
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:4689
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:3349
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:492
#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:563
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:4829
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274
static Oid findTypeSendFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1855

◆ 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  */
712  if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
713  RangeDelete(typeOid);
714 
715  ReleaseSysCache(tup);
716 
717  heap_close(relation, RowExclusiveLock);
718 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:256
#define heap_close(r, l)
Definition: heapam.h:97
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
void EnumValuesDelete(Oid enumTypeOid)
Definition: pg_enum.c:144
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 elog
Definition: elog.h:219
void RangeDelete(Oid rangeTypeOid)
Definition: pg_range.c:113

◆ RenameType()

ObjectAddress RenameType ( RenameStmt stmt)

Definition at line 3221 of file typecmds.c.

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

Referenced by ExecRenameStmt().

3222 {
3223  List *names = castNode(List, stmt->object);
3224  const char *newTypeName = stmt->newname;
3225  TypeName *typename;
3226  Oid typeOid;
3227  Relation rel;
3228  HeapTuple tup;
3229  Form_pg_type typTup;
3230  ObjectAddress address;
3231 
3232  /* Make a TypeName so we can use standard type lookup machinery */
3233  typename = makeTypeNameFromNameList(names);
3234  typeOid = typenameTypeId(NULL, typename);
3235 
3236  /* Look up the type in the type table */
3237  rel = heap_open(TypeRelationId, RowExclusiveLock);
3238 
3239  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3240  if (!HeapTupleIsValid(tup))
3241  elog(ERROR, "cache lookup failed for type %u", typeOid);
3242  typTup = (Form_pg_type) GETSTRUCT(tup);
3243 
3244  /* check permissions on type */
3245  if (!pg_type_ownercheck(typeOid, GetUserId()))
3247 
3248  /* ALTER DOMAIN used on a non-domain? */
3249  if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3250  ereport(ERROR,
3251  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3252  errmsg("%s is not a domain",
3253  format_type_be(typeOid))));
3254 
3255  /*
3256  * If it's a composite type, we need to check that it really is a
3257  * free-standing composite type, and not a table's rowtype. We want people
3258  * to use ALTER TABLE not ALTER TYPE for that case.
3259  */
3260  if (typTup->typtype == TYPTYPE_COMPOSITE &&
3261  get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3262  ereport(ERROR,
3263  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3264  errmsg("%s is a table's row type",
3265  format_type_be(typeOid)),
3266  errhint("Use ALTER TABLE instead.")));
3267 
3268  /* don't allow direct alteration of array types, either */
3269  if (OidIsValid(typTup->typelem) &&
3270  get_array_type(typTup->typelem) == typeOid)
3271  ereport(ERROR,
3272  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3273  errmsg("cannot alter array type %s",
3274  format_type_be(typeOid)),
3275  errhint("You can alter type %s, which will alter the array type as well.",
3276  format_type_be(typTup->typelem))));
3277 
3278  /*
3279  * If type is composite we need to rename associated pg_class entry too.
3280  * RenameRelationInternal will call RenameTypeInternal automatically.
3281  */
3282  if (typTup->typtype == TYPTYPE_COMPOSITE)
3283  RenameRelationInternal(typTup->typrelid, newTypeName, false);
3284  else
3285  RenameTypeInternal(typeOid, newTypeName,
3286  typTup->typnamespace);
3287 
3288  ObjectAddressSet(address, TypeRelationId, typeOid);
3289  /* Clean up */
3291 
3292  return address;
3293 }
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
Definition: tablecmds.c:3112
int errhint(const char *fmt,...)
Definition: elog.c:987
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
ObjectType renameType
Definition: parsenodes.h:2843
Oid GetUserId(void)
Definition: miscinit.c:379
#define castNode(_type_, nodeptr)
Definition: nodes.h:586
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
char * format_type_be(Oid type_oid)
Definition: format_type.c:328
#define heap_close(r, l)
Definition: heapam.h:97
char * newname
Definition: parsenodes.h:2849
unsigned int Oid
Definition: postgres_ext.h:31
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4777
#define OidIsValid(objectId)
Definition: c.h:605
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3662
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
Node * object
Definition: parsenodes.h:2846
#define ereport(elevel, rest)
Definition: elog.h:122
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:691
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 ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#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 elog
Definition: elog.h:219
Definition: pg_list.h:45
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274