PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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)
 
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, 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

#define DEFAULT_TYPDELIM   ','

Function Documentation

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

Definition at line 2471 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, NULL, ObjectAddressSet, ObjectIdGetDatum, RowExclusiveLock, SearchSysCacheCopy1, Constraint::skip_validation, typenameTypeId(), TYPEOID, TypeRelationId, and validateDomainConstraint().

Referenced by ProcessUtilitySlow().

2473 {
2474  TypeName *typename;
2475  Oid domainoid;
2476  Relation typrel;
2477  HeapTuple tup;
2478  Form_pg_type typTup;
2479  Constraint *constr;
2480  char *ccbin;
2481  ObjectAddress address;
2482 
2483  /* Make a TypeName so we can use standard type lookup machinery */
2484  typename = makeTypeNameFromNameList(names);
2485  domainoid = typenameTypeId(NULL, typename);
2486 
2487  /* Look up the domain in the type table */
2489 
2490  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2491  if (!HeapTupleIsValid(tup))
2492  elog(ERROR, "cache lookup failed for type %u", domainoid);
2493  typTup = (Form_pg_type) GETSTRUCT(tup);
2494 
2495  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2496  checkDomainOwner(tup);
2497 
2498  if (!IsA(newConstraint, Constraint))
2499  elog(ERROR, "unrecognized node type: %d",
2500  (int) nodeTag(newConstraint));
2501 
2502  constr = (Constraint *) newConstraint;
2503 
2504  switch (constr->contype)
2505  {
2506  case CONSTR_CHECK:
2507  /* processed below */
2508  break;
2509 
2510  case CONSTR_UNIQUE:
2511  ereport(ERROR,
2512  (errcode(ERRCODE_SYNTAX_ERROR),
2513  errmsg("unique constraints not possible for domains")));
2514  break;
2515 
2516  case CONSTR_PRIMARY:
2517  ereport(ERROR,
2518  (errcode(ERRCODE_SYNTAX_ERROR),
2519  errmsg("primary key constraints not possible for domains")));
2520  break;
2521 
2522  case CONSTR_EXCLUSION:
2523  ereport(ERROR,
2524  (errcode(ERRCODE_SYNTAX_ERROR),
2525  errmsg("exclusion constraints not possible for domains")));
2526  break;
2527 
2528  case CONSTR_FOREIGN:
2529  ereport(ERROR,
2530  (errcode(ERRCODE_SYNTAX_ERROR),
2531  errmsg("foreign key constraints not possible for domains")));
2532  break;
2533 
2536  case CONSTR_ATTR_DEFERRED:
2537  case CONSTR_ATTR_IMMEDIATE:
2538  ereport(ERROR,
2539  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2540  errmsg("specifying constraint deferrability not supported for domains")));
2541  break;
2542 
2543  default:
2544  elog(ERROR, "unrecognized constraint subtype: %d",
2545  (int) constr->contype);
2546  break;
2547  }
2548 
2549  /*
2550  * Since all other constraint types throw errors, this must be a check
2551  * constraint. First, process the constraint expression and add an entry
2552  * to pg_constraint.
2553  */
2554 
2555  ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
2556  typTup->typbasetype, typTup->typtypmod,
2557  constr, NameStr(typTup->typname), constrAddr);
2558 
2559  /*
2560  * If requested to validate the constraint, test all values stored in the
2561  * attributes based on the domain the constraint is being added to.
2562  */
2563  if (!constr->skip_validation)
2564  validateDomainConstraint(domainoid, ccbin);
2565 
2566  ObjectAddressSet(address, TypeRelationId, domainoid);
2567 
2568  /* Clean up */
2569  heap_close(typrel, RowExclusiveLock);
2570 
2571  return address;
2572 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
static char * domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:2989
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define nodeTag(nodeptr)
Definition: nodes.h:514
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:2969
static void validateDomainConstraint(Oid domainoid, char *ccbin)
Definition: typecmds.c:2682
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
int errmsg(const char *fmt,...)
Definition: elog.c:797
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:453
#define NameStr(name)
Definition: c.h:499
ConstrType contype
Definition: parsenodes.h:2073
#define elog
Definition: elog.h:219
bool skip_validation
Definition: parsenodes.h:2113
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274
ObjectAddress AlterDomainDefault ( List names,
Node defaultRaw 
)

Definition at line 2126 of file typecmds.c.

References Anum_pg_type_typdefault, Anum_pg_type_typdefaultbin, 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, Natts_pg_type, NIL, nodeToString(), NoLock, NULL, ObjectAddressSet, ObjectIdGetDatum, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, typenameTypeId(), TYPEOID, and TypeRelationId.

Referenced by ProcessUtilitySlow().

2127 {
2128  TypeName *typename;
2129  Oid domainoid;
2130  HeapTuple tup;
2131  ParseState *pstate;
2132  Relation rel;
2133  char *defaultValue;
2134  Node *defaultExpr = NULL; /* NULL if no default specified */
2135  Datum new_record[Natts_pg_type];
2136  bool new_record_nulls[Natts_pg_type];
2137  bool new_record_repl[Natts_pg_type];
2138  HeapTuple newtuple;
2139  Form_pg_type typTup;
2140  ObjectAddress address;
2141 
2142  /* Make a TypeName so we can use standard type lookup machinery */
2143  typename = makeTypeNameFromNameList(names);
2144  domainoid = typenameTypeId(NULL, typename);
2145 
2146  /* Look up the domain in the type table */
2148 
2149  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2150  if (!HeapTupleIsValid(tup))
2151  elog(ERROR, "cache lookup failed for type %u", domainoid);
2152  typTup = (Form_pg_type) GETSTRUCT(tup);
2153 
2154  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2155  checkDomainOwner(tup);
2156 
2157  /* Setup new tuple */
2158  MemSet(new_record, (Datum) 0, sizeof(new_record));
2159  MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2160  MemSet(new_record_repl, false, sizeof(new_record_repl));
2161 
2162  /* Store the new default into the tuple */
2163  if (defaultRaw)
2164  {
2165  /* Create a dummy ParseState for transformExpr */
2166  pstate = make_parsestate(NULL);
2167 
2168  /*
2169  * Cook the colDef->raw_expr into an expression. Note: Name is
2170  * strictly for error message
2171  */
2172  defaultExpr = cookDefault(pstate, defaultRaw,
2173  typTup->typbasetype,
2174  typTup->typtypmod,
2175  NameStr(typTup->typname));
2176 
2177  /*
2178  * If the expression is just a NULL constant, we treat the command
2179  * like ALTER ... DROP DEFAULT. (But see note for same test in
2180  * DefineDomain.)
2181  */
2182  if (defaultExpr == NULL ||
2183  (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull))
2184  {
2185  /* Default is NULL, drop it */
2186  new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2187  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2188  new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2189  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2190  }
2191  else
2192  {
2193  /*
2194  * Expression must be stored as a nodeToString result, but we also
2195  * require a valid textual representation (mainly to make life
2196  * easier for pg_dump).
2197  */
2198  defaultValue = deparse_expression(defaultExpr,
2199  NIL, false, false);
2200 
2201  /*
2202  * Form an updated tuple with the new default and write it back.
2203  */
2204  new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2205 
2206  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2207  new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2208  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2209  }
2210  }
2211  else
2212  {
2213  /* ALTER ... DROP DEFAULT */
2214  new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2215  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2216  new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2217  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2218  }
2219 
2220  newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2221  new_record, new_record_nulls,
2222  new_record_repl);
2223 
2224  CatalogTupleUpdate(rel, &tup->t_self, newtuple);
2225 
2226  /* Rebuild dependencies */
2227  GenerateTypeDependencies(typTup->typnamespace,
2228  domainoid,
2229  InvalidOid, /* typrelid is n/a */
2230  0, /* relation kind is n/a */
2231  typTup->typowner,
2232  typTup->typinput,
2233  typTup->typoutput,
2234  typTup->typreceive,
2235  typTup->typsend,
2236  typTup->typmodin,
2237  typTup->typmodout,
2238  typTup->typanalyze,
2239  InvalidOid,
2240  false, /* a domain isn't an implicit array */
2241  typTup->typbasetype,
2242  typTup->typcollation,
2243  defaultExpr,
2244  true); /* Rebuild is true */
2245 
2247 
2248  ObjectAddressSet(address, TypeRelationId, domainoid);
2249 
2250  /* Clean up */
2251  heap_close(rel, NoLock);
2252  heap_freetuple(newtuple);
2253 
2254  return address;
2255 }
#define NIL
Definition: pg_list.h:69
#define Anum_pg_type_typdefaultbin
Definition: pg_type.h:267
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Node * cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, char *attname)
Definition: heap.c:2633
#define RelationGetDescr(relation)
Definition: rel.h:428
Definition: nodes.h:509
#define MemSet(start, val, len)
Definition: c.h:858
#define heap_close(r, l)
Definition: heapam.h:97
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#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:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
#define Natts_pg_type
Definition: pg_type.h:239
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2984
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:2969
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:453
#define NameStr(name)
Definition: c.h:499
#define CStringGetTextDatum(s)
Definition: builtins.h:91
char * nodeToString(const void *obj)
Definition: outfuncs.c:4252
#define elog
Definition: elog.h:219
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:794
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:512
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274
#define Anum_pg_type_typdefault
Definition: pg_type.h:268
ObjectAddress AlterDomainDropConstraint ( List names,
const char *  constrName,
DropBehavior  behavior,
bool  missing_ok 
)

Definition at line 2381 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

2383 {
2384  TypeName *typename;
2385  Oid domainoid;
2386  HeapTuple tup;
2387  Relation rel;
2388  Relation conrel;
2389  SysScanDesc conscan;
2390  ScanKeyData key[1];
2391  HeapTuple contup;
2392  bool found = false;
2394 
2395  /* Make a TypeName so we can use standard type lookup machinery */
2396  typename = makeTypeNameFromNameList(names);
2397  domainoid = typenameTypeId(NULL, typename);
2398 
2399  /* Look up the domain in the type table */
2401 
2402  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2403  if (!HeapTupleIsValid(tup))
2404  elog(ERROR, "cache lookup failed for type %u", domainoid);
2405 
2406  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2407  checkDomainOwner(tup);
2408 
2409  /* Grab an appropriate lock on the pg_constraint relation */
2411 
2412  /* Use the index to scan only constraints of the target relation */
2413  ScanKeyInit(&key[0],
2415  BTEqualStrategyNumber, F_OIDEQ,
2417 
2418  conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2419  NULL, 1, key);
2420 
2421  /*
2422  * Scan over the result set, removing any matching entries.
2423  */
2424  while ((contup = systable_getnext(conscan)) != NULL)
2425  {
2427 
2428  if (strcmp(NameStr(con->conname), constrName) == 0)
2429  {
2430  ObjectAddress conobj;
2431 
2432  conobj.classId = ConstraintRelationId;
2433  conobj.objectId = HeapTupleGetOid(contup);
2434  conobj.objectSubId = 0;
2435 
2436  performDeletion(&conobj, behavior, 0);
2437  found = true;
2438  }
2439  }
2440 
2441  ObjectAddressSet(address, TypeRelationId, domainoid);
2442 
2443  /* Clean up after the scan */
2444  systable_endscan(conscan);
2445  heap_close(conrel, RowExclusiveLock);
2446 
2447  heap_close(rel, NoLock);
2448 
2449  if (!found)
2450  {
2451  if (!missing_ok)
2452  ereport(ERROR,
2453  (errcode(ERRCODE_UNDEFINED_OBJECT),
2454  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2455  constrName, TypeNameToString(typename))));
2456  else
2457  ereport(NOTICE,
2458  (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2459  constrName, TypeNameToString(typename))));
2460  }
2461 
2462  return address;
2463 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
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 TypeRelationId
Definition: pg_type.h:34
#define ConstraintTypidIndexId
Definition: indexing.h:128
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#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:303
#define ereport(elevel, rest)
Definition: elog.h:122
#define Anum_pg_constraint_contypid
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define NOTICE
Definition: elog.h:37
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:2969
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:453
#define NameStr(name)
Definition: c.h:499
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274
ObjectAddress AlterDomainNotNull ( List names,
bool  notNull 
)

Definition at line 2265 of file typecmds.c.

References 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, NULL, ObjectAddressSet, ObjectIdGetDatum, RegisterSnapshot(), RelToCheck::rel, RelationGetDescr, RelationGetRelationName, RowExclusiveLock, SearchSysCacheCopy1, ShareLock, HeapTupleData::t_self, TupleDescAttr, typenameTypeId(), TYPEOID, TypeRelationId, and UnregisterSnapshot().

Referenced by ProcessUtilitySlow().

2266 {
2267  TypeName *typename;
2268  Oid domainoid;
2269  Relation typrel;
2270  HeapTuple tup;
2271  Form_pg_type typTup;
2273 
2274  /* Make a TypeName so we can use standard type lookup machinery */
2275  typename = makeTypeNameFromNameList(names);
2276  domainoid = typenameTypeId(NULL, typename);
2277 
2278  /* Look up the domain in the type table */
2280 
2281  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2282  if (!HeapTupleIsValid(tup))
2283  elog(ERROR, "cache lookup failed for type %u", domainoid);
2284  typTup = (Form_pg_type) GETSTRUCT(tup);
2285 
2286  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2287  checkDomainOwner(tup);
2288 
2289  /* Is the domain already set to the desired constraint? */
2290  if (typTup->typnotnull == notNull)
2291  {
2292  heap_close(typrel, RowExclusiveLock);
2293  return address;
2294  }
2295 
2296  /* Adding a NOT NULL constraint requires checking existing columns */
2297  if (notNull)
2298  {
2299  List *rels;
2300  ListCell *rt;
2301 
2302  /* Fetch relation list with attributes based on this domain */
2303  /* ShareLock is sufficient to prevent concurrent data changes */
2304 
2305  rels = get_rels_with_domain(domainoid, ShareLock);
2306 
2307  foreach(rt, rels)
2308  {
2309  RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2310  Relation testrel = rtc->rel;
2311  TupleDesc tupdesc = RelationGetDescr(testrel);
2312  HeapScanDesc scan;
2313  HeapTuple tuple;
2314  Snapshot snapshot;
2315 
2316  /* Scan all tuples in this relation */
2317  snapshot = RegisterSnapshot(GetLatestSnapshot());
2318  scan = heap_beginscan(testrel, snapshot, 0, NULL);
2319  while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
2320  {
2321  int i;
2322 
2323  /* Test attributes that are of the domain */
2324  for (i = 0; i < rtc->natts; i++)
2325  {
2326  int attnum = rtc->atts[i];
2327  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2328 
2329  if (heap_attisnull(tuple, attnum))
2330  {
2331  /*
2332  * In principle the auxiliary information for this
2333  * error should be errdatatype(), but errtablecol()
2334  * seems considerably more useful in practice. Since
2335  * this code only executes in an ALTER DOMAIN command,
2336  * the client should already know which domain is in
2337  * question.
2338  */
2339  ereport(ERROR,
2340  (errcode(ERRCODE_NOT_NULL_VIOLATION),
2341  errmsg("column \"%s\" of table \"%s\" contains null values",
2342  NameStr(attr->attname),
2343  RelationGetRelationName(testrel)),
2344  errtablecol(testrel, attnum)));
2345  }
2346  }
2347  }
2348  heap_endscan(scan);
2349  UnregisterSnapshot(snapshot);
2350 
2351  /* Close each rel after processing, but keep lock */
2352  heap_close(testrel, NoLock);
2353  }
2354  }
2355 
2356  /*
2357  * Okay to update pg_type row. We can scribble on typTup because it's a
2358  * copy.
2359  */
2360  typTup->typnotnull = notNull;
2361 
2362  CatalogTupleUpdate(typrel, &tup->t_self, tup);
2363 
2365 
2366  ObjectAddressSet(address, TypeRelationId, domainoid);
2367 
2368  /* Clean up */
2369  heap_freetuple(tup);
2370  heap_close(typrel, RowExclusiveLock);
2371 
2372  return address;
2373 }
int * atts
Definition: typecmds.c:81
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1580
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:863
#define RelationGetDescr(relation)
Definition: rel.h:428
Relation rel
Definition: typecmds.c:79
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:84
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define NoLock
Definition: lockdefs.h:34
bool heap_attisnull(HeapTuple tup, int attnum)
Definition: heaptuple.c:296
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:436
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#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:2800
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1810
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
int errtablecol(Relation rel, int attnum)
Definition: relcache.c:5272
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
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:2969
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
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:453
#define NameStr(name)
Definition: c.h:499
#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:1397
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274
int natts
Definition: typecmds.c:80
ObjectAddress AlterDomainValidateConstraint ( List names,
char *  constrName 
)

Definition at line 2580 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

2581 {
2582  TypeName *typename;
2583  Oid domainoid;
2584  Relation typrel;
2585  Relation conrel;
2586  HeapTuple tup;
2587  Form_pg_constraint con = NULL;
2588  Form_pg_constraint copy_con;
2589  char *conbin;
2590  SysScanDesc scan;
2591  Datum val;
2592  bool found = false;
2593  bool isnull;
2594  HeapTuple tuple;
2595  HeapTuple copyTuple;
2596  ScanKeyData key;
2597  ObjectAddress address;
2598 
2599  /* Make a TypeName so we can use standard type lookup machinery */
2600  typename = makeTypeNameFromNameList(names);
2601  domainoid = typenameTypeId(NULL, typename);
2602 
2603  /* Look up the domain in the type table */
2605 
2606  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2607  if (!HeapTupleIsValid(tup))
2608  elog(ERROR, "cache lookup failed for type %u", domainoid);
2609 
2610  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2611  checkDomainOwner(tup);
2612 
2613  /*
2614  * Find and check the target constraint
2615  */
2617  ScanKeyInit(&key,
2619  BTEqualStrategyNumber, F_OIDEQ,
2620  ObjectIdGetDatum(domainoid));
2622  true, NULL, 1, &key);
2623 
2624  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2625  {
2626  con = (Form_pg_constraint) GETSTRUCT(tuple);
2627  if (strcmp(NameStr(con->conname), constrName) == 0)
2628  {
2629  found = true;
2630  break;
2631  }
2632  }
2633 
2634  if (!found)
2635  ereport(ERROR,
2636  (errcode(ERRCODE_UNDEFINED_OBJECT),
2637  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2638  constrName, TypeNameToString(typename))));
2639 
2640  if (con->contype != CONSTRAINT_CHECK)
2641  ereport(ERROR,
2642  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2643  errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2644  constrName, TypeNameToString(typename))));
2645 
2646  val = SysCacheGetAttr(CONSTROID, tuple,
2648  &isnull);
2649  if (isnull)
2650  elog(ERROR, "null conbin for constraint %u",
2651  HeapTupleGetOid(tuple));
2652  conbin = TextDatumGetCString(val);
2653 
2654  validateDomainConstraint(domainoid, conbin);
2655 
2656  /*
2657  * Now update the catalog, while we have the door open.
2658  */
2659  copyTuple = heap_copytuple(tuple);
2660  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2661  copy_con->convalidated = true;
2662  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
2663 
2665  HeapTupleGetOid(copyTuple), 0);
2666 
2667  ObjectAddressSet(address, TypeRelationId, domainoid);
2668 
2669  heap_freetuple(copyTuple);
2670 
2671  systable_endscan(scan);
2672 
2673  heap_close(typrel, AccessShareLock);
2674  heap_close(conrel, RowExclusiveLock);
2675 
2676  ReleaseSysCache(tup);
2677 
2678  return address;
2679 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:611
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
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:1373
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
#define Anum_pg_constraint_conbin
#define ConstraintTypidIndexId
Definition: indexing.h:128
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
#define CONSTRAINT_CHECK
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#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
#define Anum_pg_constraint_contypid
#define TextDatumGetCString(d)
Definition: builtins.h:92
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1279
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:2969
static void validateDomainConstraint(Oid domainoid, char *ccbin)
Definition: typecmds.c:2682
int errmsg(const char *fmt,...)
Definition: elog.c:797
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:453
#define NameStr(name)
Definition: c.h:499
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define ConstraintRelationId
Definition: pg_constraint.h:29
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
long val
Definition: informix.c:689
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274
ObjectAddress AlterEnum ( AlterEnumStmt stmt)

Definition at line 1228 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

1229 {
1230  Oid enum_type_oid;
1231  TypeName *typename;
1232  HeapTuple tup;
1233  ObjectAddress address;
1234 
1235  /* Make a TypeName so we can use standard type lookup machinery */
1236  typename = makeTypeNameFromNameList(stmt->typeName);
1237  enum_type_oid = typenameTypeId(NULL, typename);
1238 
1239  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1240  if (!HeapTupleIsValid(tup))
1241  elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1242 
1243  /* Check it's an enum and check user has permission to ALTER the enum */
1244  checkEnumOwner(tup);
1245 
1246  ReleaseSysCache(tup);
1247 
1248  if (stmt->oldVal)
1249  {
1250  /* Rename an existing label */
1251  RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
1252  }
1253  else
1254  {
1255  /* Add a new label */
1256  AddEnumLabel(enum_type_oid, stmt->newVal,
1257  stmt->newValNeighbor, stmt->newValIsAfter,
1258  stmt->skipIfNewValExists);
1259  }
1260 
1261  InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1262 
1263  ObjectAddressSet(address, TypeRelationId, enum_type_oid);
1264 
1265  return address;
1266 }
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
char * newValNeighbor
Definition: parsenodes.h:2974
static void checkEnumOwner(HeapTuple tup)
Definition: typecmds.c:1276
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
List * typeName
Definition: parsenodes.h:2971
void AddEnumLabel(Oid enumTypeOid, const char *newVal, const char *neighbor, bool newValIsAfter, bool skipIfExists)
Definition: pg_enum.c:179
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
void RenameEnumLabel(Oid enumTypeOid, const char *oldVal, const char *newVal)
Definition: pg_enum.c:471
bool skipIfNewValExists
Definition: parsenodes.h:2976
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
bool newValIsAfter
Definition: parsenodes.h:2975
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:453
#define elog
Definition: elog.h:219
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274
ObjectAddress AlterTypeNamespace ( List names,
const char *  newschema,
ObjectType  objecttype,
Oid oldschema 
)

Definition at line 3433 of file typecmds.c.

References AlterTypeNamespace_oid(), ereport, errcode(), errmsg(), ERROR, format_type_be(), free_object_addresses(), get_typtype(), LookupCreationNamespace(), makeTypeNameFromNameList(), new_object_addresses(), NULL, OBJECT_DOMAIN, ObjectAddressSet, typenameTypeId(), TypeRelationId, and TYPTYPE_DOMAIN.

Referenced by ExecAlterObjectSchemaStmt().

3435 {
3436  TypeName *typename;
3437  Oid typeOid;
3438  Oid nspOid;
3439  Oid oldNspOid;
3440  ObjectAddresses *objsMoved;
3441  ObjectAddress myself;
3442 
3443  /* Make a TypeName so we can use standard type lookup machinery */
3444  typename = makeTypeNameFromNameList(names);
3445  typeOid = typenameTypeId(NULL, typename);
3446 
3447  /* Don't allow ALTER DOMAIN on a type */
3448  if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3449  ereport(ERROR,
3450  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3451  errmsg("%s is not a domain",
3452  format_type_be(typeOid))));
3453 
3454  /* get schema OID and check its permissions */
3455  nspOid = LookupCreationNamespace(newschema);
3456 
3457  objsMoved = new_object_addresses();
3458  oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3459  free_object_addresses(objsMoved);
3460 
3461  if (oldschema)
3462  *oldschema = oldNspOid;
3463 
3464  ObjectAddressSet(myself, TypeRelationId, typeOid);
3465 
3466  return myself;
3467 }
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2896
int errcode(int sqlerrcode)
Definition: elog.c:575
char get_typtype(Oid typid)
Definition: lsyscache.c:2379
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2052
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2323
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
#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:3470
#define NULL
Definition: c.h:229
#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:453
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274
Oid AlterTypeNamespace_oid ( Oid  typeOid,
Oid  nspOid,
ObjectAddresses objsMoved 
)

Definition at line 3470 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().

3471 {
3472  Oid elemOid;
3473 
3474  /* check permissions on type */
3475  if (!pg_type_ownercheck(typeOid, GetUserId()))
3477 
3478  /* don't allow direct alteration of array types */
3479  elemOid = get_element_type(typeOid);
3480  if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3481  ereport(ERROR,
3482  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3483  errmsg("cannot alter array type %s",
3484  format_type_be(typeOid)),
3485  errhint("You can alter type %s, which will alter the array type as well.",
3486  format_type_be(elemOid))));
3487 
3488  /* and do the work */
3489  return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3490 }
int errhint(const char *fmt,...)
Definition: elog.c:987
Oid GetUserId(void)
Definition: miscinit.c:284
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2484
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2512
int errcode(int sqlerrcode)
Definition: elog.c:575
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3508
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
unsigned int Oid
Definition: postgres_ext.h:31
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4572
#define OidIsValid(objectId)
Definition: c.h:538
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3457
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg(const char *fmt,...)
Definition: elog.c:797
Oid AlterTypeNamespaceInternal ( Oid  typeOid,
Oid  nspOid,
bool  isImplicitArray,
bool  errorOnTableType,
ObjectAddresses objsMoved 
)

Definition at line 3508 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, NamespaceRelationId, NameStr, object_address_present(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, RelationRelationId, RELKIND_COMPOSITE_TYPE, RowExclusiveLock, SearchSysCacheCopy1, SearchSysCacheExists2, HeapTupleData::t_self, TYPENAMENSP, TYPEOID, TypeRelationId, TYPTYPE_COMPOSITE, and TYPTYPE_DOMAIN.

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

3512 {
3513  Relation rel;
3514  HeapTuple tup;
3515  Form_pg_type typform;
3516  Oid oldNspOid;
3517  Oid arrayOid;
3518  bool isCompositeType;
3519  ObjectAddress thisobj;
3520 
3521  /*
3522  * Make sure we haven't moved this object previously.
3523  */
3524  thisobj.classId = TypeRelationId;
3525  thisobj.objectId = typeOid;
3526  thisobj.objectSubId = 0;
3527 
3528  if (object_address_present(&thisobj, objsMoved))
3529  return InvalidOid;
3530 
3532 
3533  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3534  if (!HeapTupleIsValid(tup))
3535  elog(ERROR, "cache lookup failed for type %u", typeOid);
3536  typform = (Form_pg_type) GETSTRUCT(tup);
3537 
3538  oldNspOid = typform->typnamespace;
3539  arrayOid = typform->typarray;
3540 
3541  /* If the type is already there, we scan skip these next few checks. */
3542  if (oldNspOid != nspOid)
3543  {
3544  /* common checks on switching namespaces */
3545  CheckSetNamespace(oldNspOid, nspOid);
3546 
3547  /* check for duplicate name (more friendly than unique-index failure) */
3549  NameGetDatum(&typform->typname),
3550  ObjectIdGetDatum(nspOid)))
3551  ereport(ERROR,
3553  errmsg("type \"%s\" already exists in schema \"%s\"",
3554  NameStr(typform->typname),
3555  get_namespace_name(nspOid))));
3556  }
3557 
3558  /* Detect whether type is a composite type (but not a table rowtype) */
3559  isCompositeType =
3560  (typform->typtype == TYPTYPE_COMPOSITE &&
3561  get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3562 
3563  /* Enforce not-table-type if requested */
3564  if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3565  errorOnTableType)
3566  ereport(ERROR,
3567  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3568  errmsg("%s is a table's row type",
3569  format_type_be(typeOid)),
3570  errhint("Use ALTER TABLE instead.")));
3571 
3572  if (oldNspOid != nspOid)
3573  {
3574  /* OK, modify the pg_type row */
3575 
3576  /* tup is a copy, so we can scribble directly on it */
3577  typform->typnamespace = nspOid;
3578 
3579  CatalogTupleUpdate(rel, &tup->t_self, tup);
3580  }
3581 
3582  /*
3583  * Composite types have pg_class entries.
3584  *
3585  * We need to modify the pg_class tuple as well to reflect the change of
3586  * schema.
3587  */
3588  if (isCompositeType)
3589  {
3590  Relation classRel;
3591 
3593 
3594  AlterRelationNamespaceInternal(classRel, typform->typrelid,
3595  oldNspOid, nspOid,
3596  false, objsMoved);
3597 
3598  heap_close(classRel, RowExclusiveLock);
3599 
3600  /*
3601  * Check for constraints associated with the composite type (we don't
3602  * currently support this, but probably will someday).
3603  */
3604  AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3605  nspOid, false, objsMoved);
3606  }
3607  else
3608  {
3609  /* If it's a domain, it might have constraints */
3610  if (typform->typtype == TYPTYPE_DOMAIN)
3611  AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
3612  objsMoved);
3613  }
3614 
3615  /*
3616  * Update dependency on schema, if any --- a table rowtype has not got
3617  * one, and neither does an implicit array.
3618  */
3619  if (oldNspOid != nspOid &&
3620  (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3621  !isImplicitArray)
3622  if (changeDependencyFor(TypeRelationId, typeOid,
3623  NamespaceRelationId, oldNspOid, nspOid) != 1)
3624  elog(ERROR, "failed to change schema dependency for type %s",
3625  format_type_be(typeOid));
3626 
3628 
3629  heap_freetuple(tup);
3630 
3632 
3633  add_exact_object_address(&thisobj, objsMoved);
3634 
3635  /* Recursively alter the associated array type, if any */
3636  if (OidIsValid(arrayOid))
3637  AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
3638 
3639  return oldNspOid;
3640 }
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
#define NamespaceRelationId
Definition: pg_namespace.h:34
#define NameGetDatum(X)
Definition: postgres.h:601
int errhint(const char *fmt,...)
Definition: elog.c:987
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define TYPTYPE_COMPOSITE
Definition: pg_type.h:721
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1801
#define RelationRelationId
Definition: pg_class.h:29
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2167
int errcode(int sqlerrcode)
Definition: elog.c:575
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3508
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2107
#define heap_close(r, l)
Definition: heapam.h:97
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
#define OidIsValid(objectId)
Definition: c.h:538
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:166
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3033
#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:2928
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:176
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12573
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
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:499
#define elog
Definition: elog.h:219
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
ObjectAddress AlterTypeOwner ( List names,
Oid  newOwnerId,
ObjectType  objecttype 
)

Definition at line 3229 of file typecmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, 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(), NULL, OBJECT_DOMAIN, ObjectAddressSet, OidIsValid, pg_namespace_aclcheck(), pg_type_ownercheck(), ReleaseSysCache(), RELKIND_COMPOSITE_TYPE, RowExclusiveLock, superuser(), TypeNameToString(), TypeRelationId, typeTypeId(), TYPTYPE_COMPOSITE, and TYPTYPE_DOMAIN.

Referenced by ExecAlterOwnerStmt().

3230 {
3231  TypeName *typename;
3232  Oid typeOid;
3233  Relation rel;
3234  HeapTuple tup;
3235  HeapTuple newtup;
3236  Form_pg_type typTup;
3237  AclResult aclresult;
3238  ObjectAddress address;
3239 
3241 
3242  /* Make a TypeName so we can use standard type lookup machinery */
3243  typename = makeTypeNameFromNameList(names);
3244 
3245  /* Use LookupTypeName here so that shell types can be processed */
3246  tup = LookupTypeName(NULL, typename, NULL, false);
3247  if (tup == NULL)
3248  ereport(ERROR,
3249  (errcode(ERRCODE_UNDEFINED_OBJECT),
3250  errmsg("type \"%s\" does not exist",
3251  TypeNameToString(typename))));
3252  typeOid = typeTypeId(tup);
3253 
3254  /* Copy the syscache entry so we can scribble on it below */
3255  newtup = heap_copytuple(tup);
3256  ReleaseSysCache(tup);
3257  tup = newtup;
3258  typTup = (Form_pg_type) GETSTRUCT(tup);
3259 
3260  /* Don't allow ALTER DOMAIN on a type */
3261  if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3262  ereport(ERROR,
3263  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3264  errmsg("%s is not a domain",
3265  format_type_be(typeOid))));
3266 
3267  /*
3268  * If it's a composite type, we need to check that it really is a
3269  * free-standing composite type, and not a table's rowtype. We want people
3270  * to use ALTER TABLE not ALTER TYPE for that case.
3271  */
3272  if (typTup->typtype == TYPTYPE_COMPOSITE &&
3273  get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3274  ereport(ERROR,
3275  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3276  errmsg("%s is a table's row type",
3277  format_type_be(typeOid)),
3278  errhint("Use ALTER TABLE instead.")));
3279 
3280  /* don't allow direct alteration of array types, either */
3281  if (OidIsValid(typTup->typelem) &&
3282  get_array_type(typTup->typelem) == typeOid)
3283  ereport(ERROR,
3284  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3285  errmsg("cannot alter array type %s",
3286  format_type_be(typeOid)),
3287  errhint("You can alter type %s, which will alter the array type as well.",
3288  format_type_be(typTup->typelem))));
3289 
3290  /*
3291  * If the new owner is the same as the existing owner, consider the
3292  * command to have succeeded. This is for dump restoration purposes.
3293  */
3294  if (typTup->typowner != newOwnerId)
3295  {
3296  /* Superusers can always do it */
3297  if (!superuser())
3298  {
3299  /* Otherwise, must be owner of the existing object */
3302 
3303  /* Must be able to become new owner */
3304  check_is_member_of_role(GetUserId(), newOwnerId);
3305 
3306  /* New owner must have CREATE privilege on namespace */
3307  aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3308  newOwnerId,
3309  ACL_CREATE);
3310  if (aclresult != ACLCHECK_OK)
3312  get_namespace_name(typTup->typnamespace));
3313  }
3314 
3315  AlterTypeOwner_oid(typeOid, newOwnerId, true);
3316  }
3317 
3318  ObjectAddressSet(address, TypeRelationId, typeOid);
3319 
3320  /* Clean up */
3322 
3323  return address;
3324 }
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:611
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
int errhint(const char *fmt,...)
Definition: elog.c:987
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Oid GetUserId(void)
Definition: miscinit.c:284
#define TYPTYPE_COMPOSITE
Definition: pg_type.h:721
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:459
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2512
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1801
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:94
#define heap_close(r, l)
Definition: heapam.h:97
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
unsigned int Oid
Definition: postgres_ext.h:31
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4572
#define TypeRelationId
Definition: pg_type.h:34
#define OidIsValid(objectId)
Definition: c.h:538
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4484
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:166
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3457
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:82
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition: typecmds.c:3338
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3033
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define RowExclusiveLock
Definition: lockdefs.h:38
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4859
#define ereport(elevel, rest)
Definition: elog.h:122
AclResult
Definition: acl.h:170
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define NULL
Definition: c.h:229
#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:453
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
Oid typeTypeId(Type tp)
Definition: parse_type.c:571
void AlterTypeOwner_oid ( Oid  typeOid,
Oid  newOwnerId,
bool  hasDependEntry 
)

Definition at line 3338 of file typecmds.c.

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

Referenced by AlterTypeOwner(), and shdepReassignOwned().

3339 {
3340  Relation rel;
3341  HeapTuple tup;
3342  Form_pg_type typTup;
3343 
3345 
3346  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3347  if (!HeapTupleIsValid(tup))
3348  elog(ERROR, "cache lookup failed for type %u", typeOid);
3349  typTup = (Form_pg_type) GETSTRUCT(tup);
3350 
3351  /*
3352  * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3353  * the pg_class entry properly. That will call back to
3354  * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3355  */
3356  if (typTup->typtype == TYPTYPE_COMPOSITE)
3357  ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3358  else
3359  AlterTypeOwnerInternal(typeOid, newOwnerId);
3360 
3361  /* Update owner dependency reference */
3362  if (hasDependEntry)
3363  changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3364 
3366 
3367  ReleaseSysCache(tup);
3369 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define TYPTYPE_COMPOSITE
Definition: pg_type.h:721
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3378
#define heap_close(r, l)
Definition: heapam.h:97
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
#define TypeRelationId
Definition: pg_type.h:34
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:304
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#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:9840
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define elog
Definition: elog.h:219
void AlterTypeOwnerInternal ( Oid  typeOid,
Oid  newOwnerId 
)

Definition at line 3378 of file typecmds.c.

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

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

3379 {
3380  Relation rel;
3381  HeapTuple tup;
3382  Form_pg_type typTup;
3383  Datum repl_val[Natts_pg_type];
3384  bool repl_null[Natts_pg_type];
3385  bool repl_repl[Natts_pg_type];
3386  Acl *newAcl;
3387  Datum aclDatum;
3388  bool isNull;
3389 
3391 
3392  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3393  if (!HeapTupleIsValid(tup))
3394  elog(ERROR, "cache lookup failed for type %u", typeOid);
3395  typTup = (Form_pg_type) GETSTRUCT(tup);
3396 
3397  memset(repl_null, false, sizeof(repl_null));
3398  memset(repl_repl, false, sizeof(repl_repl));
3399 
3400  repl_repl[Anum_pg_type_typowner - 1] = true;
3401  repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
3402 
3403  aclDatum = heap_getattr(tup,
3405  RelationGetDescr(rel),
3406  &isNull);
3407  /* Null ACLs do not require changes */
3408  if (!isNull)
3409  {
3410  newAcl = aclnewowner(DatumGetAclP(aclDatum),
3411  typTup->typowner, newOwnerId);
3412  repl_repl[Anum_pg_type_typacl - 1] = true;
3413  repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3414  }
3415 
3416  tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3417  repl_repl);
3418 
3419  CatalogTupleUpdate(rel, &tup->t_self, tup);
3420 
3421  /* If it has an array type, update that too */
3422  if (OidIsValid(typTup->typarray))
3423  AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
3424 
3425  /* Clean up */
3427 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define RelationGetDescr(relation)
Definition: rel.h:428
#define DatumGetAclP(X)
Definition: acl.h:113
#define PointerGetDatum(X)
Definition: postgres.h:562
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3378
#define heap_close(r, l)
Definition: heapam.h:97
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
#define TypeRelationId
Definition: pg_type.h:34
#define OidIsValid(objectId)
Definition: c.h:538
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#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:769
uintptr_t Datum
Definition: postgres.h:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define Natts_pg_type
Definition: pg_type.h:239
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Anum_pg_type_typacl
Definition: pg_type.h:269
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
#define elog
Definition: elog.h:219
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:794
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1035
#define Anum_pg_type_typowner
Definition: pg_type.h:242
Oid AssignTypeArrayOid ( void  )

Definition at line 2027 of file typecmds.c.

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

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

2028 {
2029  Oid type_array_oid;
2030 
2031  /* Use binary-upgrade override for pg_type.typarray? */
2032  if (IsBinaryUpgrade)
2033  {
2035  ereport(ERROR,
2036  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2037  errmsg("pg_type array OID value not set when in binary upgrade mode")));
2038 
2039  type_array_oid = binary_upgrade_next_array_pg_type_oid;
2041  }
2042  else
2043  {
2045 
2046  type_array_oid = GetNewOid(pg_type);
2047  heap_close(pg_type, AccessShareLock);
2048  }
2049 
2050  return type_array_oid;
2051 }
#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 TypeRelationId
Definition: pg_type.h:34
#define OidIsValid(objectId)
Definition: c.h:538
bool IsBinaryUpgrade
Definition: globals.c:102
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
Oid GetNewOid(Relation relation)
Definition: catalog.c:289
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
Oid binary_upgrade_next_array_pg_type_oid
Definition: typecmds.c:86
int errmsg(const char *fmt,...)
Definition: elog.c:797
void checkDomainOwner ( HeapTuple  tup)

Definition at line 2969 of file typecmds.c.

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

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

2970 {
2971  Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2972 
2973  /* Check that this is actually a domain */
2974  if (typTup->typtype != TYPTYPE_DOMAIN)
2975  ereport(ERROR,
2976  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2977  errmsg("%s is not a domain",
2979 
2980  /* Permission check: must own type */
2983 }
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Oid GetUserId(void)
Definition: miscinit.c:284
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4572
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3457
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
ObjectAddress DefineCompositeType ( RangeVar typevar,
List coldeflist 
)

Definition at line 2068 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, NULL, ObjectIdGetDatum, OidIsValid, CreateStmt::oncommit, ONCOMMIT_NOOP, CreateStmt::options, RangeVarAdjustRelationPersistence(), RangeVarGetAndCheckCreationNamespace(), CreateStmt::relation, RELKIND_COMPOSITE_TYPE, RangeVar::relname, CreateStmt::tableElts, CreateStmt::tablespacename, and TYPENAMENSP.

Referenced by ProcessUtilitySlow().

2069 {
2070  CreateStmt *createStmt = makeNode(CreateStmt);
2071  Oid old_type_oid;
2072  Oid typeNamespace;
2073  ObjectAddress address;
2074 
2075  /*
2076  * now set the parameters for keys/inheritance etc. All of these are
2077  * uninteresting for composite types...
2078  */
2079  createStmt->relation = typevar;
2080  createStmt->tableElts = coldeflist;
2081  createStmt->inhRelations = NIL;
2082  createStmt->constraints = NIL;
2083  createStmt->options = NIL;
2084  createStmt->oncommit = ONCOMMIT_NOOP;
2085  createStmt->tablespacename = NULL;
2086  createStmt->if_not_exists = false;
2087 
2088  /*
2089  * Check for collision with an existing type name. If there is one and
2090  * it's an autogenerated array, we can rename it out of the way. This
2091  * check is here mainly to get a better error message about a "type"
2092  * instead of below about a "relation".
2093  */
2094  typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2095  NoLock, NULL);
2096  RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2097  old_type_oid =
2099  CStringGetDatum(createStmt->relation->relname),
2100  ObjectIdGetDatum(typeNamespace));
2101  if (OidIsValid(old_type_oid))
2102  {
2103  if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2104  ereport(ERROR,
2106  errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2107  }
2108 
2109  /*
2110  * Finally create the relation. This also creates the type.
2111  */
2112  DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2113  NULL);
2114 
2115  return address;
2116 }
RangeVar * relation
Definition: parsenodes.h:1995
#define NIL
Definition: pg_list.h:69
OnCommitAction oncommit
Definition: parsenodes.h:2004
List * inhRelations
Definition: parsenodes.h:1997
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition: namespace.c:615
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:166
#define GetSysCacheOid2(cacheId, key1, key2)
Definition: syscache.h:185
List * constraints
Definition: parsenodes.h:2002
bool if_not_exists
Definition: parsenodes.h:2006
char * relname
Definition: primnodes.h:68
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:833
#define NoLock
Definition: lockdefs.h:34
#define CStringGetDatum(X)
Definition: postgres.h:584
List * options
Definition: parsenodes.h:2003
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:503
#define ereport(elevel, rest)
Definition: elog.h:122
char * tablespacename
Definition: parsenodes.h:2005
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:508
#define InvalidOid
Definition: postgres_ext.h:36
List * tableElts
Definition: parsenodes.h:1996
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
ObjectAddress DefineDomain ( CreateDomainStmt stmt)

Definition at line 729 of file typecmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, Anum_pg_type_typdefault, Anum_pg_type_typdefaultbin, TypeName::arrayBounds, 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(), moveArrayTypeName(), NIL, nodeTag, nodeToString(), NULL, ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, pg_namespace_aclcheck(), pg_type_aclcheck(), QualifiedNameGetCreationNamespace(), Constraint::raw_expr, ReleaseSysCache(), SysCacheGetAttr(), TextDatumGetCString, TypeCreate(), CreateDomainStmt::typeName, TYPENAMENSP, TypeNameToString(), typenameType(), TYPEOID, TYPTYPE_BASE, TYPTYPE_DOMAIN, TYPTYPE_ENUM, and TYPTYPE_RANGE.

Referenced by ProcessUtilitySlow().

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

Definition at line 1107 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

1108 {
1109  char *enumName;
1110  char *enumArrayName;
1111  Oid enumNamespace;
1112  AclResult aclresult;
1113  Oid old_type_oid;
1114  Oid enumArrayOid;
1115  ObjectAddress enumTypeAddr;
1116 
1117  /* Convert list of names to a name and namespace */
1118  enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1119  &enumName);
1120 
1121  /* Check we have creation rights in target namespace */
1122  aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1123  if (aclresult != ACLCHECK_OK)
1125  get_namespace_name(enumNamespace));
1126 
1127  /*
1128  * Check for collision with an existing type name. If there is one and
1129  * it's an autogenerated array, we can rename it out of the way.
1130  */
1131  old_type_oid = GetSysCacheOid2(TYPENAMENSP,
1132  CStringGetDatum(enumName),
1133  ObjectIdGetDatum(enumNamespace));
1134  if (OidIsValid(old_type_oid))
1135  {
1136  if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1137  ereport(ERROR,
1139  errmsg("type \"%s\" already exists", enumName)));
1140  }
1141 
1142  enumArrayOid = AssignTypeArrayOid();
1143 
1144  /* Create the pg_type entry */
1145  enumTypeAddr =
1146  TypeCreate(InvalidOid, /* no predetermined type OID */
1147  enumName, /* type name */
1148  enumNamespace, /* namespace */
1149  InvalidOid, /* relation oid (n/a here) */
1150  0, /* relation kind (ditto) */
1151  GetUserId(), /* owner's ID */
1152  sizeof(Oid), /* internal size */
1153  TYPTYPE_ENUM, /* type-type (enum type) */
1154  TYPCATEGORY_ENUM, /* type-category (enum type) */
1155  false, /* enum types are never preferred */
1156  DEFAULT_TYPDELIM, /* array element delimiter */
1157  F_ENUM_IN, /* input procedure */
1158  F_ENUM_OUT, /* output procedure */
1159  F_ENUM_RECV, /* receive procedure */
1160  F_ENUM_SEND, /* send procedure */
1161  InvalidOid, /* typmodin procedure - none */
1162  InvalidOid, /* typmodout procedure - none */
1163  InvalidOid, /* analyze procedure - default */
1164  InvalidOid, /* element type ID */
1165  false, /* this is not an array type */
1166  enumArrayOid, /* array type we are about to create */
1167  InvalidOid, /* base type ID (only for domains) */
1168  NULL, /* never a default type value */
1169  NULL, /* binary default isn't sent either */
1170  true, /* always passed by value */
1171  'i', /* int alignment */
1172  'p', /* TOAST strategy always plain */
1173  -1, /* typMod (Domains only) */
1174  0, /* Array dimensions of typbasetype */
1175  false, /* Type NOT NULL */
1176  InvalidOid); /* type's collation */
1177 
1178  /* Enter the enum's values into pg_enum */
1179  EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
1180 
1181  /*
1182  * Create the array type that goes with it.
1183  */
1184  enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1185 
1186  TypeCreate(enumArrayOid, /* force assignment of this type OID */
1187  enumArrayName, /* type name */
1188  enumNamespace, /* namespace */
1189  InvalidOid, /* relation oid (n/a here) */
1190  0, /* relation kind (ditto) */
1191  GetUserId(), /* owner's ID */
1192  -1, /* internal size (always varlena) */
1193  TYPTYPE_BASE, /* type-type (base type) */
1194  TYPCATEGORY_ARRAY, /* type-category (array) */
1195  false, /* array types are never preferred */
1196  DEFAULT_TYPDELIM, /* array element delimiter */
1197  F_ARRAY_IN, /* input procedure */
1198  F_ARRAY_OUT, /* output procedure */
1199  F_ARRAY_RECV, /* receive procedure */
1200  F_ARRAY_SEND, /* send procedure */
1201  InvalidOid, /* typmodin procedure - none */
1202  InvalidOid, /* typmodout procedure - none */
1203  F_ARRAY_TYPANALYZE, /* analyze procedure */
1204  enumTypeAddr.objectId, /* element type ID */
1205  true, /* yes this is an array type */
1206  InvalidOid, /* no further array type */
1207  InvalidOid, /* base type ID */
1208  NULL, /* never a default type value */
1209  NULL, /* binary default isn't sent either */
1210  false, /* never passed by value */
1211  'i', /* enums have align i, so do their arrays */
1212  'x', /* ARRAY is always toastable */
1213  -1, /* typMod (Domains only) */
1214  0, /* Array dimensions of typbasetype */
1215  false, /* Type NOT NULL */
1216  InvalidOid); /* type's collation */
1217 
1218  pfree(enumArrayName);
1219 
1220  return enumTypeAddr;
1221 }
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:767
#define TYPTYPE_BASE
Definition: pg_type.h:720
Oid GetUserId(void)
Definition: miscinit.c:284
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2956
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:538
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4484
#define TYPCATEGORY_ENUM
Definition: pg_type.h:732
#define GetSysCacheOid2(cacheId, key1, key2)
Definition: syscache.h:185
void pfree(void *pointer)
Definition: mcxt.c:950
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:82
#define TYPCATEGORY_ARRAY
Definition: pg_type.h:728
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3033
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:833
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define CStringGetDatum(X)
Definition: postgres.h:584
#define ereport(elevel, rest)
Definition: elog.h:122
AclResult
Definition: acl.h:170
#define InvalidOid
Definition: postgres_ext.h:36
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22
#define NULL
Definition: c.h:229
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2027
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:195
#define TYPTYPE_ENUM
Definition: pg_type.h:723
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
ObjectAddress DefineRange ( CreateRangeStmt stmt)

Definition at line 1298 of file typecmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, 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, NULL, ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, CreateRangeStmt::params, pfree(), pg_namespace_aclcheck(), pg_strcasecmp(), QualifiedNameGetCreationNamespace(), RangeCreate(), TYPCATEGORY_ARRAY, TYPCATEGORY_RANGE, type_is_collatable(), TypeCreate(), CreateRangeStmt::typeName, TYPENAMENSP, typenameTypeId(), TypeShellMake(), TYPTYPE_BASE, TYPTYPE_PSEUDO, and TYPTYPE_RANGE.

Referenced by ProcessUtilitySlow().

1299 {
1300  char *typeName;
1301  Oid typeNamespace;
1302  Oid typoid;
1303  char *rangeArrayName;
1304  Oid rangeArrayOid;
1305  Oid rangeSubtype = InvalidOid;
1306  List *rangeSubOpclassName = NIL;
1307  List *rangeCollationName = NIL;
1308  List *rangeCanonicalName = NIL;
1309  List *rangeSubtypeDiffName = NIL;
1310  Oid rangeSubOpclass;
1311  Oid rangeCollation;
1312  regproc rangeCanonical;
1313  regproc rangeSubtypeDiff;
1314  int16 subtyplen;
1315  bool subtypbyval;
1316  char subtypalign;
1317  char alignment;
1318  AclResult aclresult;
1319  ListCell *lc;
1320  ObjectAddress address;
1321 
1322  /* Convert list of names to a name and namespace */
1323  typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1324  &typeName);
1325 
1326  /* Check we have creation rights in target namespace */
1327  aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1328  if (aclresult != ACLCHECK_OK)
1330  get_namespace_name(typeNamespace));
1331 
1332  /*
1333  * Look to see if type already exists.
1334  */
1335  typoid = GetSysCacheOid2(TYPENAMENSP,
1336  CStringGetDatum(typeName),
1337  ObjectIdGetDatum(typeNamespace));
1338 
1339  /*
1340  * If it's not a shell, see if it's an autogenerated array type, and if so
1341  * rename it out of the way.
1342  */
1343  if (OidIsValid(typoid) && get_typisdefined(typoid))
1344  {
1345  if (moveArrayTypeName(typoid, typeName, typeNamespace))
1346  typoid = InvalidOid;
1347  else
1348  ereport(ERROR,
1350  errmsg("type \"%s\" already exists", typeName)));
1351  }
1352 
1353  /*
1354  * If it doesn't exist, create it as a shell, so that the OID is known for
1355  * use in the range function definitions.
1356  */
1357  if (!OidIsValid(typoid))
1358  {
1359  address = TypeShellMake(typeName, typeNamespace, GetUserId());
1360  typoid = address.objectId;
1361  /* Make new shell type visible for modification below */
1363  }
1364 
1365  /* Extract the parameters from the parameter list */
1366  foreach(lc, stmt->params)
1367  {
1368  DefElem *defel = (DefElem *) lfirst(lc);
1369 
1370  if (pg_strcasecmp(defel->defname, "subtype") == 0)
1371  {
1372  if (OidIsValid(rangeSubtype))
1373  ereport(ERROR,
1374  (errcode(ERRCODE_SYNTAX_ERROR),
1375  errmsg("conflicting or redundant options")));
1376  /* we can look up the subtype name immediately */
1377  rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1378  }
1379  else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
1380  {
1381  if (rangeSubOpclassName != NIL)
1382  ereport(ERROR,
1383  (errcode(ERRCODE_SYNTAX_ERROR),
1384  errmsg("conflicting or redundant options")));
1385  rangeSubOpclassName = defGetQualifiedName(defel);
1386  }
1387  else if (pg_strcasecmp(defel->defname, "collation") == 0)
1388  {
1389  if (rangeCollationName != NIL)
1390  ereport(ERROR,
1391  (errcode(ERRCODE_SYNTAX_ERROR),
1392  errmsg("conflicting or redundant options")));
1393  rangeCollationName = defGetQualifiedName(defel);
1394  }
1395  else if (pg_strcasecmp(defel->defname, "canonical") == 0)
1396  {
1397  if (rangeCanonicalName != NIL)
1398  ereport(ERROR,
1399  (errcode(ERRCODE_SYNTAX_ERROR),
1400  errmsg("conflicting or redundant options")));
1401  rangeCanonicalName = defGetQualifiedName(defel);
1402  }
1403  else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
1404  {
1405  if (rangeSubtypeDiffName != NIL)
1406  ereport(ERROR,
1407  (errcode(ERRCODE_SYNTAX_ERROR),
1408  errmsg("conflicting or redundant options")));
1409  rangeSubtypeDiffName = defGetQualifiedName(defel);
1410  }
1411  else
1412  ereport(ERROR,
1413  (errcode(ERRCODE_SYNTAX_ERROR),
1414  errmsg("type attribute \"%s\" not recognized",
1415  defel->defname)));
1416  }
1417 
1418  /* Must have a subtype */
1419  if (!OidIsValid(rangeSubtype))
1420  ereport(ERROR,
1421  (errcode(ERRCODE_SYNTAX_ERROR),
1422  errmsg("type attribute \"subtype\" is required")));
1423  /* disallow ranges of pseudotypes */
1424  if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
1425  ereport(ERROR,
1426  (errcode(ERRCODE_DATATYPE_MISMATCH),
1427  errmsg("range subtype cannot be %s",
1428  format_type_be(rangeSubtype))));
1429 
1430  /* Identify subopclass */
1431  rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1432 
1433  /* Identify collation to use, if any */
1434  if (type_is_collatable(rangeSubtype))
1435  {
1436  if (rangeCollationName != NIL)
1437  rangeCollation = get_collation_oid(rangeCollationName, false);
1438  else
1439  rangeCollation = get_typcollation(rangeSubtype);
1440  }
1441  else
1442  {
1443  if (rangeCollationName != NIL)
1444  ereport(ERROR,
1445  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1446  errmsg("range collation specified but subtype does not support collation")));
1447  rangeCollation = InvalidOid;
1448  }
1449 
1450  /* Identify support functions, if provided */
1451  if (rangeCanonicalName != NIL)
1452  rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1453  typoid);
1454  else
1455  rangeCanonical = InvalidOid;
1456 
1457  if (rangeSubtypeDiffName != NIL)
1458  rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1459  rangeSubtype);
1460  else
1461  rangeSubtypeDiff = InvalidOid;
1462 
1463  get_typlenbyvalalign(rangeSubtype,
1464  &subtyplen, &subtypbyval, &subtypalign);
1465 
1466  /* alignment must be 'i' or 'd' for ranges */
1467  alignment = (subtypalign == 'd') ? 'd' : 'i';
1468 
1469  /* Allocate OID for array type */
1470  rangeArrayOid = AssignTypeArrayOid();
1471 
1472  /* Create the pg_type entry */
1473  address =
1474  TypeCreate(InvalidOid, /* no predetermined type OID */
1475  typeName, /* type name */
1476  typeNamespace, /* namespace */
1477  InvalidOid, /* relation oid (n/a here) */
1478  0, /* relation kind (ditto) */
1479  GetUserId(), /* owner's ID */
1480  -1, /* internal size (always varlena) */
1481  TYPTYPE_RANGE, /* type-type (range type) */
1482  TYPCATEGORY_RANGE, /* type-category (range type) */
1483  false, /* range types are never preferred */
1484  DEFAULT_TYPDELIM, /* array element delimiter */
1485  F_RANGE_IN, /* input procedure */
1486  F_RANGE_OUT, /* output procedure */
1487  F_RANGE_RECV, /* receive procedure */
1488  F_RANGE_SEND, /* send procedure */
1489  InvalidOid, /* typmodin procedure - none */
1490  InvalidOid, /* typmodout procedure - none */
1491  F_RANGE_TYPANALYZE, /* analyze procedure */
1492  InvalidOid, /* element type ID - none */
1493  false, /* this is not an array type */
1494  rangeArrayOid, /* array type we are about to create */
1495  InvalidOid, /* base type ID (only for domains) */
1496  NULL, /* never a default type value */
1497  NULL, /* no binary form available either */
1498  false, /* never passed by value */
1499  alignment, /* alignment */
1500  'x', /* TOAST strategy (always extended) */
1501  -1, /* typMod (Domains only) */
1502  0, /* Array dimensions of typbasetype */
1503  false, /* Type NOT NULL */
1504  InvalidOid); /* type's collation (ranges never have one) */
1505  Assert(typoid == address.objectId);
1506 
1507  /* Create the entry in pg_range */
1508  RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1509  rangeCanonical, rangeSubtypeDiff);
1510 
1511  /*
1512  * Create the array type that goes with it.
1513  */
1514  rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1515 
1516  TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1517  rangeArrayName, /* type name */
1518  typeNamespace, /* namespace */
1519  InvalidOid, /* relation oid (n/a here) */
1520  0, /* relation kind (ditto) */
1521  GetUserId(), /* owner's ID */
1522  -1, /* internal size (always varlena) */
1523  TYPTYPE_BASE, /* type-type (base type) */
1524  TYPCATEGORY_ARRAY, /* type-category (array) */
1525  false, /* array types are never preferred */
1526  DEFAULT_TYPDELIM, /* array element delimiter */
1527  F_ARRAY_IN, /* input procedure */
1528  F_ARRAY_OUT, /* output procedure */
1529  F_ARRAY_RECV, /* receive procedure */
1530  F_ARRAY_SEND, /* send procedure */
1531  InvalidOid, /* typmodin procedure - none */
1532  InvalidOid, /* typmodout procedure - none */
1533  F_ARRAY_TYPANALYZE, /* analyze procedure */
1534  typoid, /* element type ID */
1535  true, /* yes this is an array type */
1536  InvalidOid, /* no further array type */
1537  InvalidOid, /* base type ID */
1538  NULL, /* never a default type value */
1539  NULL, /* binary default isn't sent either */
1540  false, /* never passed by value */
1541  alignment, /* alignment - same as range's */
1542  'x', /* ARRAY is always toastable */
1543  -1, /* typMod (Domains only) */
1544  0, /* Array dimensions of typbasetype */
1545  false, /* Type NOT NULL */
1546  InvalidOid); /* typcollation */
1547 
1548  pfree(rangeArrayName);
1549 
1550  /* And create the constructor functions for this range type */
1551  makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1552 
1553  return address;
1554 }
signed short int16
Definition: c.h:255
#define NIL
Definition: pg_list.h:69
static void makeRangeConstructors(const char *name, Oid namespace, Oid rangeOid, Oid subtype)
Definition: typecmds.c:1566
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:767
#define TYPTYPE_BASE
Definition: pg_type.h:720
Oid GetUserId(void)
Definition: miscinit.c:284
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2956
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2021
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:1923
int errcode(int sqlerrcode)
Definition: elog.c:575
char get_typtype(Oid typid)
Definition: lsyscache.c:2379
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
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:56
#define OidIsValid(objectId)
Definition: c.h:538
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4484
#define GetSysCacheOid2(cacheId, key1, key2)
Definition: syscache.h:185
static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype)
Definition: typecmds.c:1979
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:255
#define TYPCATEGORY_RANGE
Definition: pg_type.h:737
void pfree(void *pointer)
Definition: mcxt.c:950
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:82
#define TYPCATEGORY_ARRAY
Definition: pg_type.h:728
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:3033
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:833
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define CStringGetDatum(X)
Definition: postgres.h:584
#define ereport(elevel, rest)
Definition: elog.h:122
#define TYPTYPE_RANGE
Definition: pg_type.h:725
AclResult
Definition: acl.h:170
void CommandCounterIncrement(void)
Definition: xact.c:922
#define InvalidOid
Definition: postgres_ext.h:36
static Oid findRangeSubOpclass(List *opcname, Oid subtype)
Definition: typecmds.c:1899
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:2781
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
#define lfirst(lc)
Definition: pg_list.h:106
List * defGetQualifiedName(DefElem *def)
Definition: define.c:223
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2027
#define TYPTYPE_PSEUDO
Definition: pg_type.h:724
Oid regproc
Definition: c.h:394
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:195
char * defname
Definition: parsenodes.h:719
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:2806
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3493
Definition: pg_list.h:45
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1938
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274
ObjectAddress DefineType ( ParseState pstate,
List names,
List parameters 
)

Definition at line 116 of file typecmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, ACL_KIND_PROC, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, Assert, AssignTypeArrayOid(), BYTEAOID, CommandCounterIncrement(), CStringGetDatum, CSTRINGOID, DEFAULT_COLLATION_OID, 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, NULL, ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, OPAQUEOID, parser_errposition(), pfree(), pg_namespace_aclcheck(), pg_proc_ownercheck(), pg_strcasecmp(), PROVOLATILE_VOLATILE, QualifiedNameGetCreationNamespace(), ReleaseSysCache(), SetFunctionReturnType(), superuser(), TYPCATEGORY_ARRAY, TYPCATEGORY_USER, TypeCreate(), TYPENAMENSP, typenameType(), typenameTypeId(), TypeShellMake(), TYPTYPE_BASE, TYPTYPE_PSEUDO, and WARNING.

Referenced by ProcessUtilitySlow().

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

Definition at line 689 of file typecmds.c.

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

Referenced by doDeletion().

690 {
691  Relation relation;
692  HeapTuple tup;
693 
695 
696  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
697  if (!HeapTupleIsValid(tup))
698  elog(ERROR, "cache lookup failed for type %u", typeOid);
699 
700  CatalogTupleDelete(relation, &tup->t_self);
701 
702  /*
703  * If it is an enum, delete the pg_enum entries too; we don't bother with
704  * making dependency entries for those, so it has to be done "by hand"
705  * here.
706  */
707  if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
708  EnumValuesDelete(typeOid);
709 
710  /*
711  * If it is a range type, delete the pg_range entry too; we don't bother
712  * with making a dependency entry for that, so it has to be done "by hand"
713  * here.
714  */
715  if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
716  RangeDelete(typeOid);
717 
718  ReleaseSysCache(tup);
719 
720  heap_close(relation, RowExclusiveLock);
721 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:255
#define heap_close(r, l)
Definition: heapam.h:97
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
#define TypeRelationId
Definition: pg_type.h:34
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#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
#define TYPTYPE_RANGE
Definition: pg_type.h:725
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define TYPTYPE_ENUM
Definition: pg_type.h:723
#define elog
Definition: elog.h:219
void RangeDelete(Oid rangeTypeOid)
Definition: pg_range.c:113
ObjectAddress RenameType ( RenameStmt stmt)

Definition at line 3151 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, NULL, RenameStmt::object, OBJECT_DOMAIN, ObjectAddressSet, ObjectIdGetDatum, OidIsValid, pg_type_ownercheck(), RELKIND_COMPOSITE_TYPE, RenameRelationInternal(), RenameStmt::renameType, RenameTypeInternal(), RowExclusiveLock, SearchSysCacheCopy1, typenameTypeId(), TYPEOID, TypeRelationId, TYPTYPE_COMPOSITE, and TYPTYPE_DOMAIN.

Referenced by ExecRenameStmt().

3152 {
3153  List *names = castNode(List, stmt->object);
3154  const char *newTypeName = stmt->newname;
3155  TypeName *typename;
3156  Oid typeOid;
3157  Relation rel;
3158  HeapTuple tup;
3159  Form_pg_type typTup;
3160  ObjectAddress address;
3161 
3162  /* Make a TypeName so we can use standard type lookup machinery */
3163  typename = makeTypeNameFromNameList(names);
3164  typeOid = typenameTypeId(NULL, typename);
3165 
3166  /* Look up the type in the type table */
3168 
3169  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3170  if (!HeapTupleIsValid(tup))
3171  elog(ERROR, "cache lookup failed for type %u", typeOid);
3172  typTup = (Form_pg_type) GETSTRUCT(tup);
3173 
3174  /* check permissions on type */
3175  if (!pg_type_ownercheck(typeOid, GetUserId()))
3177 
3178  /* ALTER DOMAIN used on a non-domain? */
3179  if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3180  ereport(ERROR,
3181  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3182  errmsg("%s is not a domain",
3183  format_type_be(typeOid))));
3184 
3185  /*
3186  * If it's a composite type, we need to check that it really is a
3187  * free-standing composite type, and not a table's rowtype. We want people
3188  * to use ALTER TABLE not ALTER TYPE for that case.
3189  */
3190  if (typTup->typtype == TYPTYPE_COMPOSITE &&
3191  get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3192  ereport(ERROR,
3193  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3194  errmsg("%s is a table's row type",
3195  format_type_be(typeOid)),
3196  errhint("Use ALTER TABLE instead.")));
3197 
3198  /* don't allow direct alteration of array types, either */
3199  if (OidIsValid(typTup->typelem) &&
3200  get_array_type(typTup->typelem) == typeOid)
3201  ereport(ERROR,
3202  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3203  errmsg("cannot alter array type %s",
3204  format_type_be(typeOid)),
3205  errhint("You can alter type %s, which will alter the array type as well.",
3206  format_type_be(typTup->typelem))));
3207 
3208  /*
3209  * If type is composite we need to rename associated pg_class entry too.
3210  * RenameRelationInternal will call RenameTypeInternal automatically.
3211  */
3212  if (typTup->typtype == TYPTYPE_COMPOSITE)
3213  RenameRelationInternal(typTup->typrelid, newTypeName, false);
3214  else
3215  RenameTypeInternal(typeOid, newTypeName,
3216  typTup->typnamespace);
3217 
3218  ObjectAddressSet(address, TypeRelationId, typeOid);
3219  /* Clean up */
3221 
3222  return address;
3223 }
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
Definition: tablecmds.c:2922
int errhint(const char *fmt,...)
Definition: elog.c:987
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
ObjectType renameType
Definition: parsenodes.h:2794
Oid GetUserId(void)
Definition: miscinit.c:284
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
#define TYPTYPE_COMPOSITE
Definition: pg_type.h:721
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2512
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1801
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
#define heap_close(r, l)
Definition: heapam.h:97
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
char * newname
Definition: parsenodes.h:2800
unsigned int Oid
Definition: postgres_ext.h:31
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4572
#define TypeRelationId
Definition: pg_type.h:34
#define OidIsValid(objectId)
Definition: c.h:538
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:166
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3457
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
Node * object
Definition: parsenodes.h:2797
#define ereport(elevel, rest)
Definition: elog.h:122
void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
Definition: pg_type.c:692
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
int errmsg(const char *fmt,...)
Definition: elog.c:797
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:453
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274