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

2472 {
2473  TypeName *typename;
2474  Oid domainoid;
2475  Relation typrel;
2476  HeapTuple tup;
2477  Form_pg_type typTup;
2478  Constraint *constr;
2479  char *ccbin;
2480  ObjectAddress address;
2481 
2482  /* Make a TypeName so we can use standard type lookup machinery */
2483  typename = makeTypeNameFromNameList(names);
2484  domainoid = typenameTypeId(NULL, typename);
2485 
2486  /* Look up the domain in the type table */
2488 
2489  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2490  if (!HeapTupleIsValid(tup))
2491  elog(ERROR, "cache lookup failed for type %u", domainoid);
2492  typTup = (Form_pg_type) GETSTRUCT(tup);
2493 
2494  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2495  checkDomainOwner(tup);
2496 
2497  if (!IsA(newConstraint, Constraint))
2498  elog(ERROR, "unrecognized node type: %d",
2499  (int) nodeTag(newConstraint));
2500 
2501  constr = (Constraint *) newConstraint;
2502 
2503  switch (constr->contype)
2504  {
2505  case CONSTR_CHECK:
2506  /* processed below */
2507  break;
2508 
2509  case CONSTR_UNIQUE:
2510  ereport(ERROR,
2511  (errcode(ERRCODE_SYNTAX_ERROR),
2512  errmsg("unique constraints not possible for domains")));
2513  break;
2514 
2515  case CONSTR_PRIMARY:
2516  ereport(ERROR,
2517  (errcode(ERRCODE_SYNTAX_ERROR),
2518  errmsg("primary key constraints not possible for domains")));
2519  break;
2520 
2521  case CONSTR_EXCLUSION:
2522  ereport(ERROR,
2523  (errcode(ERRCODE_SYNTAX_ERROR),
2524  errmsg("exclusion constraints not possible for domains")));
2525  break;
2526 
2527  case CONSTR_FOREIGN:
2528  ereport(ERROR,
2529  (errcode(ERRCODE_SYNTAX_ERROR),
2530  errmsg("foreign key constraints not possible for domains")));
2531  break;
2532 
2535  case CONSTR_ATTR_DEFERRED:
2536  case CONSTR_ATTR_IMMEDIATE:
2537  ereport(ERROR,
2538  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2539  errmsg("specifying constraint deferrability not supported for domains")));
2540  break;
2541 
2542  default:
2543  elog(ERROR, "unrecognized constraint subtype: %d",
2544  (int) constr->contype);
2545  break;
2546  }
2547 
2548  /*
2549  * Since all other constraint types throw errors, this must be a check
2550  * constraint. First, process the constraint expression and add an entry
2551  * to pg_constraint.
2552  */
2553 
2554  ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
2555  typTup->typbasetype, typTup->typtypmod,
2556  constr, NameStr(typTup->typname), constrAddr);
2557 
2558  /*
2559  * If requested to validate the constraint, test all values stored in the
2560  * attributes based on the domain the constraint is being added to.
2561  */
2562  if (!constr->skip_validation)
2563  validateDomainConstraint(domainoid, ccbin);
2564 
2565  ObjectAddressSet(address, TypeRelationId, domainoid);
2566 
2567  /* Clean up */
2568  heap_close(typrel, RowExclusiveLock);
2569 
2570  return address;
2571 }
#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:2972
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#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:2952
static void validateDomainConstraint(Oid domainoid, char *ccbin)
Definition: typecmds.c:2681
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:161
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:2045
#define elog
Definition: elog.h:219
bool skip_validation
Definition: parsenodes.h:2084
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:2636
#define RelationGetDescr(relation)
Definition: rel.h:429
Definition: nodes.h:509
#define MemSet(start, val, len)
Definition: c.h:857
#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:1374
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:1284
#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:2947
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:2952
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:161
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:4217
#define elog
Definition: elog.h:219
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:793
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 2380 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().

2382 {
2383  TypeName *typename;
2384  Oid domainoid;
2385  HeapTuple tup;
2386  Relation rel;
2387  Relation conrel;
2388  SysScanDesc conscan;
2389  ScanKeyData key[1];
2390  HeapTuple contup;
2391  bool found = false;
2393 
2394  /* Make a TypeName so we can use standard type lookup machinery */
2395  typename = makeTypeNameFromNameList(names);
2396  domainoid = typenameTypeId(NULL, typename);
2397 
2398  /* Look up the domain in the type table */
2400 
2401  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2402  if (!HeapTupleIsValid(tup))
2403  elog(ERROR, "cache lookup failed for type %u", domainoid);
2404 
2405  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2406  checkDomainOwner(tup);
2407 
2408  /* Grab an appropriate lock on the pg_constraint relation */
2410 
2411  /* Use the index to scan only constraints of the target relation */
2412  ScanKeyInit(&key[0],
2414  BTEqualStrategyNumber, F_OIDEQ,
2416 
2417  conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true,
2418  NULL, 1, key);
2419 
2420  /*
2421  * Scan over the result set, removing any matching entries.
2422  */
2423  while ((contup = systable_getnext(conscan)) != NULL)
2424  {
2426 
2427  if (strcmp(NameStr(con->conname), constrName) == 0)
2428  {
2429  ObjectAddress conobj;
2430 
2431  conobj.classId = ConstraintRelationId;
2432  conobj.objectId = HeapTupleGetOid(contup);
2433  conobj.objectSubId = 0;
2434 
2435  performDeletion(&conobj, behavior, 0);
2436  found = true;
2437  }
2438  }
2439 
2440  ObjectAddressSet(address, TypeRelationId, domainoid);
2441 
2442  /* Clean up after the scan */
2443  systable_endscan(conscan);
2444  heap_close(conrel, RowExclusiveLock);
2445 
2446  heap_close(rel, NoLock);
2447 
2448  if (!found)
2449  {
2450  if (!missing_ok)
2451  ereport(ERROR,
2452  (errcode(ERRCODE_UNDEFINED_OBJECT),
2453  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2454  constrName, TypeNameToString(typename))));
2455  else
2456  ereport(NOTICE,
2457  (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2458  constrName, TypeNameToString(typename))));
2459  }
2460 
2461  return address;
2462 }
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:1284
#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:2952
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:161
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 tupleDesc::attrs, 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, 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 
2328  if (heap_attisnull(tuple, attnum))
2329  {
2330  /*
2331  * In principle the auxiliary information for this
2332  * error should be errdatatype(), but errtablecol()
2333  * seems considerably more useful in practice. Since
2334  * this code only executes in an ALTER DOMAIN command,
2335  * the client should already know which domain is in
2336  * question.
2337  */
2338  ereport(ERROR,
2339  (errcode(ERRCODE_NOT_NULL_VIOLATION),
2340  errmsg("column \"%s\" of table \"%s\" contains null values",
2341  NameStr(tupdesc->attrs[attnum - 1]->attname),
2342  RelationGetRelationName(testrel)),
2343  errtablecol(testrel, attnum)));
2344  }
2345  }
2346  }
2347  heap_endscan(scan);
2348  UnregisterSnapshot(snapshot);
2349 
2350  /* Close each rel after processing, but keep lock */
2351  heap_close(testrel, NoLock);
2352  }
2353  }
2354 
2355  /*
2356  * Okay to update pg_type row. We can scribble on typTup because it's a
2357  * copy.
2358  */
2359  typTup->typnotnull = notNull;
2360 
2361  CatalogTupleUpdate(typrel, &tup->t_self, tup);
2362 
2364 
2365  ObjectAddressSet(address, TypeRelationId, domainoid);
2366 
2367  /* Clean up */
2368  heap_freetuple(tup);
2369  heap_close(typrel, RowExclusiveLock);
2370 
2371  return address;
2372 }
int * atts
Definition: typecmds.c:81
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
void heap_endscan(HeapScanDesc scan)
Definition: heapam.c:1578
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:858
#define RelationGetDescr(relation)
Definition: rel.h:429
Relation rel
Definition: typecmds.c:79
Form_pg_attribute * attrs
Definition: tupdesc.h:74
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:1374
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:297
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:437
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:900
static List * get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
Definition: typecmds.c:2799
HeapTuple heap_getnext(HeapScanDesc scan, ScanDirection direction)
Definition: heapam.c:1794
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#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:5249
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:375
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:2952
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:161
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:1391
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 2579 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().

2580 {
2581  TypeName *typename;
2582  Oid domainoid;
2583  Relation typrel;
2584  Relation conrel;
2585  HeapTuple tup;
2586  Form_pg_constraint con = NULL;
2587  Form_pg_constraint copy_con;
2588  char *conbin;
2589  SysScanDesc scan;
2590  Datum val;
2591  bool found = false;
2592  bool isnull;
2593  HeapTuple tuple;
2594  HeapTuple copyTuple;
2595  ScanKeyData key;
2596  ObjectAddress address;
2597 
2598  /* Make a TypeName so we can use standard type lookup machinery */
2599  typename = makeTypeNameFromNameList(names);
2600  domainoid = typenameTypeId(NULL, typename);
2601 
2602  /* Look up the domain in the type table */
2604 
2605  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2606  if (!HeapTupleIsValid(tup))
2607  elog(ERROR, "cache lookup failed for type %u", domainoid);
2608 
2609  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2610  checkDomainOwner(tup);
2611 
2612  /*
2613  * Find and check the target constraint
2614  */
2616  ScanKeyInit(&key,
2618  BTEqualStrategyNumber, F_OIDEQ,
2619  ObjectIdGetDatum(domainoid));
2621  true, NULL, 1, &key);
2622 
2623  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2624  {
2625  con = (Form_pg_constraint) GETSTRUCT(tuple);
2626  if (strcmp(NameStr(con->conname), constrName) == 0)
2627  {
2628  found = true;
2629  break;
2630  }
2631  }
2632 
2633  if (!found)
2634  ereport(ERROR,
2635  (errcode(ERRCODE_UNDEFINED_OBJECT),
2636  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2637  constrName, TypeNameToString(typename))));
2638 
2639  if (con->contype != CONSTRAINT_CHECK)
2640  ereport(ERROR,
2641  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2642  errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2643  constrName, TypeNameToString(typename))));
2644 
2645  val = SysCacheGetAttr(CONSTROID, tuple,
2647  &isnull);
2648  if (isnull)
2649  elog(ERROR, "null conbin for constraint %u",
2650  HeapTupleGetOid(tuple));
2651  conbin = TextDatumGetCString(val);
2652 
2653  validateDomainConstraint(domainoid, conbin);
2654 
2655  /*
2656  * Now update the catalog, while we have the door open.
2657  */
2658  copyTuple = heap_copytuple(tuple);
2659  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2660  copy_con->convalidated = true;
2661  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
2662 
2664  HeapTupleGetOid(copyTuple), 0);
2665 
2666  ObjectAddressSet(address, TypeRelationId, domainoid);
2667 
2668  heap_freetuple(copyTuple);
2669 
2670  systable_endscan(scan);
2671 
2672  heap_close(typrel, AccessShareLock);
2673  heap_close(conrel, RowExclusiveLock);
2674 
2675  ReleaseSysCache(tup);
2676 
2677  return address;
2678 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:608
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:1374
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:152
#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:1116
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1278
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
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:2952
static void validateDomainConstraint(Oid domainoid, char *ccbin)
Definition: typecmds.c:2681
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:152
char * newValNeighbor
Definition: parsenodes.h:2945
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:2942
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:2947
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
bool newValIsAfter
Definition: parsenodes.h:2946
#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 3416 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().

3418 {
3419  TypeName *typename;
3420  Oid typeOid;
3421  Oid nspOid;
3422  Oid oldNspOid;
3423  ObjectAddresses *objsMoved;
3424  ObjectAddress myself;
3425 
3426  /* Make a TypeName so we can use standard type lookup machinery */
3427  typename = makeTypeNameFromNameList(names);
3428  typeOid = typenameTypeId(NULL, typename);
3429 
3430  /* Don't allow ALTER DOMAIN on a type */
3431  if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3432  ereport(ERROR,
3433  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3434  errmsg("%s is not a domain",
3435  format_type_be(typeOid))));
3436 
3437  /* get schema OID and check its permissions */
3438  nspOid = LookupCreationNamespace(newschema);
3439 
3440  objsMoved = new_object_addresses();
3441  oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3442  free_object_addresses(objsMoved);
3443 
3444  if (oldschema)
3445  *oldschema = oldNspOid;
3446 
3447  ObjectAddressSet(myself, TypeRelationId, typeOid);
3448 
3449  return myself;
3450 }
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2786
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:2039
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2310
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:3453
#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 3453 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().

3454 {
3455  Oid elemOid;
3456 
3457  /* check permissions on type */
3458  if (!pg_type_ownercheck(typeOid, GetUserId()))
3460 
3461  /* don't allow direct alteration of array types */
3462  elemOid = get_element_type(typeOid);
3463  if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3464  ereport(ERROR,
3465  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3466  errmsg("cannot alter array type %s",
3467  format_type_be(typeOid)),
3468  errhint("You can alter type %s, which will alter the array type as well.",
3469  format_type_be(elemOid))));
3470 
3471  /* and do the work */
3472  return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3473 }
int errhint(const char *fmt,...)
Definition: elog.c:987
Oid GetUserId(void)
Definition: miscinit.c:283
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:3491
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 3491 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().

3495 {
3496  Relation rel;
3497  HeapTuple tup;
3498  Form_pg_type typform;
3499  Oid oldNspOid;
3500  Oid arrayOid;
3501  bool isCompositeType;
3502  ObjectAddress thisobj;
3503 
3504  /*
3505  * Make sure we haven't moved this object previously.
3506  */
3507  thisobj.classId = TypeRelationId;
3508  thisobj.objectId = typeOid;
3509  thisobj.objectSubId = 0;
3510 
3511  if (object_address_present(&thisobj, objsMoved))
3512  return InvalidOid;
3513 
3515 
3516  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3517  if (!HeapTupleIsValid(tup))
3518  elog(ERROR, "cache lookup failed for type %u", typeOid);
3519  typform = (Form_pg_type) GETSTRUCT(tup);
3520 
3521  oldNspOid = typform->typnamespace;
3522  arrayOid = typform->typarray;
3523 
3524  /* If the type is already there, we scan skip these next few checks. */
3525  if (oldNspOid != nspOid)
3526  {
3527  /* common checks on switching namespaces */
3528  CheckSetNamespace(oldNspOid, nspOid);
3529 
3530  /* check for duplicate name (more friendly than unique-index failure) */
3532  NameGetDatum(&typform->typname),
3533  ObjectIdGetDatum(nspOid)))
3534  ereport(ERROR,
3536  errmsg("type \"%s\" already exists in schema \"%s\"",
3537  NameStr(typform->typname),
3538  get_namespace_name(nspOid))));
3539  }
3540 
3541  /* Detect whether type is a composite type (but not a table rowtype) */
3542  isCompositeType =
3543  (typform->typtype == TYPTYPE_COMPOSITE &&
3544  get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3545 
3546  /* Enforce not-table-type if requested */
3547  if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3548  errorOnTableType)
3549  ereport(ERROR,
3550  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3551  errmsg("%s is a table's row type",
3552  format_type_be(typeOid)),
3553  errhint("Use ALTER TABLE instead.")));
3554 
3555  if (oldNspOid != nspOid)
3556  {
3557  /* OK, modify the pg_type row */
3558 
3559  /* tup is a copy, so we can scribble directly on it */
3560  typform->typnamespace = nspOid;
3561 
3562  CatalogTupleUpdate(rel, &tup->t_self, tup);
3563  }
3564 
3565  /*
3566  * Composite types have pg_class entries.
3567  *
3568  * We need to modify the pg_class tuple as well to reflect the change of
3569  * schema.
3570  */
3571  if (isCompositeType)
3572  {
3573  Relation classRel;
3574 
3576 
3577  AlterRelationNamespaceInternal(classRel, typform->typrelid,
3578  oldNspOid, nspOid,
3579  false, objsMoved);
3580 
3581  heap_close(classRel, RowExclusiveLock);
3582 
3583  /*
3584  * Check for constraints associated with the composite type (we don't
3585  * currently support this, but probably will someday).
3586  */
3587  AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3588  nspOid, false, objsMoved);
3589  }
3590  else
3591  {
3592  /* If it's a domain, it might have constraints */
3593  if (typform->typtype == TYPTYPE_DOMAIN)
3594  AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
3595  objsMoved);
3596  }
3597 
3598  /*
3599  * Update dependency on schema, if any --- a table rowtype has not got
3600  * one, and neither does an implicit array.
3601  */
3602  if (oldNspOid != nspOid &&
3603  (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3604  !isImplicitArray)
3605  if (changeDependencyFor(TypeRelationId, typeOid,
3606  NamespaceRelationId, oldNspOid, nspOid) != 1)
3607  elog(ERROR, "failed to change schema dependency for type %s",
3608  format_type_be(typeOid));
3609 
3611 
3612  heap_freetuple(tup);
3613 
3615 
3616  add_exact_object_address(&thisobj, objsMoved);
3617 
3618  /* Recursively alter the associated array type, if any */
3619  if (OidIsValid(arrayOid))
3620  AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
3621 
3622  return oldNspOid;
3623 }
#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:2154
int errcode(int sqlerrcode)
Definition: elog.c:575
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3491
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:2094
#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:1374
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:3038
#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:2818
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#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:172
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:12538
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:161
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:31
ObjectAddress AlterTypeOwner ( List names,
Oid  newOwnerId,
ObjectType  objecttype 
)

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

3213 {
3214  TypeName *typename;
3215  Oid typeOid;
3216  Relation rel;
3217  HeapTuple tup;
3218  HeapTuple newtup;
3219  Form_pg_type typTup;
3220  AclResult aclresult;
3221  ObjectAddress address;
3222 
3224 
3225  /* Make a TypeName so we can use standard type lookup machinery */
3226  typename = makeTypeNameFromNameList(names);
3227 
3228  /* Use LookupTypeName here so that shell types can be processed */
3229  tup = LookupTypeName(NULL, typename, NULL, false);
3230  if (tup == NULL)
3231  ereport(ERROR,
3232  (errcode(ERRCODE_UNDEFINED_OBJECT),
3233  errmsg("type \"%s\" does not exist",
3234  TypeNameToString(typename))));
3235  typeOid = typeTypeId(tup);
3236 
3237  /* Copy the syscache entry so we can scribble on it below */
3238  newtup = heap_copytuple(tup);
3239  ReleaseSysCache(tup);
3240  tup = newtup;
3241  typTup = (Form_pg_type) GETSTRUCT(tup);
3242 
3243  /* Don't allow ALTER DOMAIN on a type */
3244  if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3245  ereport(ERROR,
3246  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3247  errmsg("%s is not a domain",
3248  format_type_be(typeOid))));
3249 
3250  /*
3251  * If it's a composite type, we need to check that it really is a
3252  * free-standing composite type, and not a table's rowtype. We want people
3253  * to use ALTER TABLE not ALTER TYPE for that case.
3254  */
3255  if (typTup->typtype == TYPTYPE_COMPOSITE &&
3256  get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3257  ereport(ERROR,
3258  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3259  errmsg("%s is a table's row type",
3260  format_type_be(typeOid)),
3261  errhint("Use ALTER TABLE instead.")));
3262 
3263  /* don't allow direct alteration of array types, either */
3264  if (OidIsValid(typTup->typelem) &&
3265  get_array_type(typTup->typelem) == typeOid)
3266  ereport(ERROR,
3267  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3268  errmsg("cannot alter array type %s",
3269  format_type_be(typeOid)),
3270  errhint("You can alter type %s, which will alter the array type as well.",
3271  format_type_be(typTup->typelem))));
3272 
3273  /*
3274  * If the new owner is the same as the existing owner, consider the
3275  * command to have succeeded. This is for dump restoration purposes.
3276  */
3277  if (typTup->typowner != newOwnerId)
3278  {
3279  /* Superusers can always do it */
3280  if (!superuser())
3281  {
3282  /* Otherwise, must be owner of the existing object */
3285 
3286  /* Must be able to become new owner */
3287  check_is_member_of_role(GetUserId(), newOwnerId);
3288 
3289  /* New owner must have CREATE privilege on namespace */
3290  aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3291  newOwnerId,
3292  ACL_CREATE);
3293  if (aclresult != ACLCHECK_OK)
3295  get_namespace_name(typTup->typnamespace));
3296  }
3297 
3298  AlterTypeOwner_oid(typeOid, newOwnerId, true);
3299  }
3300 
3301  ObjectAddressSet(address, TypeRelationId, typeOid);
3302 
3303  /* Clean up */
3305 
3306  return address;
3307 }
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:608
#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:283
#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:3321
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3038
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:1116
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#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 3321 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().

3322 {
3323  Relation rel;
3324  HeapTuple tup;
3325  Form_pg_type typTup;
3326 
3328 
3329  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3330  if (!HeapTupleIsValid(tup))
3331  elog(ERROR, "cache lookup failed for type %u", typeOid);
3332  typTup = (Form_pg_type) GETSTRUCT(tup);
3333 
3334  /*
3335  * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3336  * the pg_class entry properly. That will call back to
3337  * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3338  */
3339  if (typTup->typtype == TYPTYPE_COMPOSITE)
3340  ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3341  else
3342  AlterTypeOwnerInternal(typeOid, newOwnerId);
3343 
3344  /* Update owner dependency reference */
3345  if (hasDependEntry)
3346  changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3347 
3349 
3350  ReleaseSysCache(tup);
3352 }
#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:3361
#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:152
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:9826
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define AccessExclusiveLock
Definition: lockdefs.h:46
#define elog
Definition: elog.h:219
void AlterTypeOwnerInternal ( Oid  typeOid,
Oid  newOwnerId 
)

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

3362 {
3363  Relation rel;
3364  HeapTuple tup;
3365  Form_pg_type typTup;
3366  Datum repl_val[Natts_pg_type];
3367  bool repl_null[Natts_pg_type];
3368  bool repl_repl[Natts_pg_type];
3369  Acl *newAcl;
3370  Datum aclDatum;
3371  bool isNull;
3372 
3374 
3375  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3376  if (!HeapTupleIsValid(tup))
3377  elog(ERROR, "cache lookup failed for type %u", typeOid);
3378  typTup = (Form_pg_type) GETSTRUCT(tup);
3379 
3380  memset(repl_null, false, sizeof(repl_null));
3381  memset(repl_repl, false, sizeof(repl_repl));
3382 
3383  repl_repl[Anum_pg_type_typowner - 1] = true;
3384  repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
3385 
3386  aclDatum = heap_getattr(tup,
3388  RelationGetDescr(rel),
3389  &isNull);
3390  /* Null ACLs do not require changes */
3391  if (!isNull)
3392  {
3393  newAcl = aclnewowner(DatumGetAclP(aclDatum),
3394  typTup->typowner, newOwnerId);
3395  repl_repl[Anum_pg_type_typacl - 1] = true;
3396  repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3397  }
3398 
3399  tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3400  repl_repl);
3401 
3402  CatalogTupleUpdate(rel, &tup->t_self, tup);
3403 
3404  /* If it has an array type, update that too */
3405  if (OidIsValid(typTup->typarray))
3406  AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
3407 
3408  /* Clean up */
3410 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define RelationGetDescr(relation)
Definition: rel.h:429
#define DatumGetAclP(X)
Definition: acl.h:113
#define PointerGetDatum(X)
Definition: postgres.h:562
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3361
#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:1284
#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:161
#define elog
Definition: elog.h:219
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:793
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:101
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
Oid GetNewOid(Relation relation)
Definition: catalog.c:288
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#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 2952 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().

2953 {
2954  Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2955 
2956  /* Check that this is actually a domain */
2957  if (typTup->typtype != TYPTYPE_DOMAIN)
2958  ereport(ERROR,
2959  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2960  errmsg("%s is not a domain",
2962 
2963  /* Permission check: must own type */
2966 }
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Oid GetUserId(void)
Definition: miscinit.c:283
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:1967
#define NIL
Definition: pg_list.h:69
OnCommitAction oncommit
Definition: parsenodes.h:1976
List * inhRelations
Definition: parsenodes.h:1969
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:614
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:166
#define GetSysCacheOid2(cacheId, key1, key2)
Definition: syscache.h:181
List * constraints
Definition: parsenodes.h:1974
bool if_not_exists
Definition: parsenodes.h:1978
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:813
#define NoLock
Definition: lockdefs.h:34
#define CStringGetDatum(X)
Definition: postgres.h:584
List * options
Definition: parsenodes.h:1975
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:489
#define ereport(elevel, rest)
Definition: elog.h:122
char * tablespacename
Definition: parsenodes.h:1977
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:507
#define InvalidOid
Definition: postgres_ext.h:36
List * tableElts
Definition: parsenodes.h:1968
#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:31
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:2636
#define TYPTYPE_BASE
Definition: pg_type.h:720
Oid GetUserId(void)
Definition: miscinit.c:283
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2846
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:459
Node * raw_expr
Definition: parsenodes.h:2055
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:181
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
CollateClause * collClause
Definition: parsenodes.h:2473
#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:3038
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:813
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:2972
#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:1116
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1278
#define InvalidOid
Definition: postgres_ext.h:36
bool is_no_inherit
Definition: parsenodes.h:2054
#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:2947
static int list_length(const List *l)
Definition: pg_list.h:89
#define nodeTag(nodeptr)
Definition: nodes.h:514
TypeName * typeName
Definition: parsenodes.h:2472
List * collname
Definition: parsenodes.h:310
List * arrayBounds
Definition: parsenodes.h:215
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:4217
ConstrType contype
Definition: parsenodes.h:2045
#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:31
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3380
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:747
#define TYPTYPE_BASE
Definition: pg_type.h:720
Oid GetUserId(void)
Definition: miscinit.c:283
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2846
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:181
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:3038
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:813
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:31
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:747
#define TYPTYPE_BASE
Definition: pg_type.h:720
Oid GetUserId(void)
Definition: miscinit.c:283
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2846
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:181
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:3038
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:813
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:675
#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:31
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3380
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:747
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:283
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2846
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:181
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:3038
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:813
#define DEFAULT_COLLATION_OID
Definition: pg_collation.h:74
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:5481
#define WARNING
Definition: elog.h:40
char * NameListToString(List *names)
Definition: namespace.c:2953
void CommandCounterIncrement(void)
Definition: xact.c:922
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
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:675
#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:31
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:152
#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:1116
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#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 3134 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().

3135 {
3136  List *names = castNode(List, stmt->object);
3137  const char *newTypeName = stmt->newname;
3138  TypeName *typename;
3139  Oid typeOid;
3140  Relation rel;
3141  HeapTuple tup;
3142  Form_pg_type typTup;
3143  ObjectAddress address;
3144 
3145  /* Make a TypeName so we can use standard type lookup machinery */
3146  typename = makeTypeNameFromNameList(names);
3147  typeOid = typenameTypeId(NULL, typename);
3148 
3149  /* Look up the type in the type table */
3151 
3152  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3153  if (!HeapTupleIsValid(tup))
3154  elog(ERROR, "cache lookup failed for type %u", typeOid);
3155  typTup = (Form_pg_type) GETSTRUCT(tup);
3156 
3157  /* check permissions on type */
3158  if (!pg_type_ownercheck(typeOid, GetUserId()))
3160 
3161  /* ALTER DOMAIN used on a non-domain? */
3162  if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3163  ereport(ERROR,
3164  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3165  errmsg("\"%s\" is not a domain",
3166  format_type_be(typeOid))));
3167 
3168  /*
3169  * If it's a composite type, we need to check that it really is a
3170  * free-standing composite type, and not a table's rowtype. We want people
3171  * to use ALTER TABLE not ALTER TYPE for that case.
3172  */
3173  if (typTup->typtype == TYPTYPE_COMPOSITE &&
3174  get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3175  ereport(ERROR,
3176  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3177  errmsg("%s is a table's row type",
3178  format_type_be(typeOid)),
3179  errhint("Use ALTER TABLE instead.")));
3180 
3181  /* don't allow direct alteration of array types, either */
3182  if (OidIsValid(typTup->typelem) &&
3183  get_array_type(typTup->typelem) == typeOid)
3184  ereport(ERROR,
3185  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3186  errmsg("cannot alter array type %s",
3187  format_type_be(typeOid)),
3188  errhint("You can alter type %s, which will alter the array type as well.",
3189  format_type_be(typTup->typelem))));
3190 
3191  /*
3192  * If type is composite we need to rename associated pg_class entry too.
3193  * RenameRelationInternal will call RenameTypeInternal automatically.
3194  */
3195  if (typTup->typtype == TYPTYPE_COMPOSITE)
3196  RenameRelationInternal(typTup->typrelid, newTypeName, false);
3197  else
3198  RenameTypeInternal(typeOid, newTypeName,
3199  typTup->typnamespace);
3200 
3201  ObjectAddressSet(address, TypeRelationId, typeOid);
3202  /* Clean up */
3204 
3205  return address;
3206 }
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
Definition: tablecmds.c:2919
int errhint(const char *fmt,...)
Definition: elog.c:987
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
ObjectType renameType
Definition: parsenodes.h:2765
Oid GetUserId(void)
Definition: miscinit.c:283
#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:2771
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:2768
#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:1284
#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:161
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