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, bool isTopLevel)
 
ObjectAddress DefineCompositeType (RangeVar *typevar, List *coldeflist)
 
Oid AssignTypeArrayOid (void)
 
ObjectAddress AlterDomainDefault (List *names, Node *defaultRaw)
 
ObjectAddress AlterDomainNotNull (List *names, bool notNull)
 
ObjectAddress AlterDomainAddConstraint (List *names, Node *constr, ObjectAddress *constrAddr)
 
ObjectAddress AlterDomainValidateConstraint (List *names, 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 2540 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

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

Definition at line 2195 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, ObjectAddressSet, ObjectIdGetDatum, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, typenameTypeId(), TYPEOID, and TypeRelationId.

Referenced by ProcessUtilitySlow().

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

Definition at line 2450 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, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, performDeletion(), RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, systable_beginscan(), systable_endscan(), systable_getnext(), TypeNameToString(), typenameTypeId(), TYPEOID, and TypeRelationId.

Referenced by ProcessUtilitySlow().

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

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

Referenced by ProcessUtilitySlow().

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

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

2650 {
2651  TypeName *typename;
2652  Oid domainoid;
2653  Relation typrel;
2654  Relation conrel;
2655  HeapTuple tup;
2656  Form_pg_constraint con = NULL;
2657  Form_pg_constraint copy_con;
2658  char *conbin;
2659  SysScanDesc scan;
2660  Datum val;
2661  bool found = false;
2662  bool isnull;
2663  HeapTuple tuple;
2664  HeapTuple copyTuple;
2665  ScanKeyData key;
2666  ObjectAddress address;
2667 
2668  /* Make a TypeName so we can use standard type lookup machinery */
2669  typename = makeTypeNameFromNameList(names);
2670  domainoid = typenameTypeId(NULL, typename);
2671 
2672  /* Look up the domain in the type table */
2674 
2675  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2676  if (!HeapTupleIsValid(tup))
2677  elog(ERROR, "cache lookup failed for type %u", domainoid);
2678 
2679  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2680  checkDomainOwner(tup);
2681 
2682  /*
2683  * Find and check the target constraint
2684  */
2686  ScanKeyInit(&key,
2688  BTEqualStrategyNumber, F_OIDEQ,
2689  ObjectIdGetDatum(domainoid));
2691  true, NULL, 1, &key);
2692 
2693  while (HeapTupleIsValid(tuple = systable_getnext(scan)))
2694  {
2695  con = (Form_pg_constraint) GETSTRUCT(tuple);
2696  if (strcmp(NameStr(con->conname), constrName) == 0)
2697  {
2698  found = true;
2699  break;
2700  }
2701  }
2702 
2703  if (!found)
2704  ereport(ERROR,
2705  (errcode(ERRCODE_UNDEFINED_OBJECT),
2706  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2707  constrName, TypeNameToString(typename))));
2708 
2709  if (con->contype != CONSTRAINT_CHECK)
2710  ereport(ERROR,
2711  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2712  errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2713  constrName, TypeNameToString(typename))));
2714 
2715  val = SysCacheGetAttr(CONSTROID, tuple,
2717  &isnull);
2718  if (isnull)
2719  elog(ERROR, "null conbin for constraint %u",
2720  HeapTupleGetOid(tuple));
2721  conbin = TextDatumGetCString(val);
2722 
2723  validateDomainConstraint(domainoid, conbin);
2724 
2725  /*
2726  * Now update the catalog, while we have the door open.
2727  */
2728  copyTuple = heap_copytuple(tuple);
2729  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2730  copy_con->convalidated = true;
2731  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
2732 
2734  HeapTupleGetOid(copyTuple), 0);
2735 
2736  ObjectAddressSet(address, TypeRelationId, domainoid);
2737 
2738  heap_freetuple(copyTuple);
2739 
2740  systable_endscan(scan);
2741 
2742  heap_close(typrel, AccessShareLock);
2743  heap_close(conrel, RowExclusiveLock);
2744 
2745  ReleaseSysCache(tup);
2746 
2747  return address;
2748 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:611
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:459
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
#define TypeRelationId
Definition: pg_type.h:34
#define Anum_pg_constraint_conbin
#define ConstraintTypidIndexId
Definition: indexing.h:128
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
#define 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
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
#define TextDatumGetCString(d)
Definition: builtins.h:92
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1368
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
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:3038
static void validateDomainConstraint(Oid domainoid, char *ccbin)
Definition: typecmds.c:2751
int errmsg(const char *fmt,...)
Definition: elog.c:797
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:453
#define NameStr(name)
Definition: c.h:493
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,
bool  isTopLevel 
)

Definition at line 1276 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

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

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

Referenced by ExecAlterObjectSchemaStmt().

3504 {
3505  TypeName *typename;
3506  Oid typeOid;
3507  Oid nspOid;
3508  Oid oldNspOid;
3509  ObjectAddresses *objsMoved;
3510  ObjectAddress myself;
3511 
3512  /* Make a TypeName so we can use standard type lookup machinery */
3513  typename = makeTypeNameFromNameList(names);
3514  typeOid = typenameTypeId(NULL, typename);
3515 
3516  /* Don't allow ALTER DOMAIN on a type */
3517  if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3518  ereport(ERROR,
3519  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3520  errmsg("%s is not a domain",
3521  format_type_be(typeOid))));
3522 
3523  /* get schema OID and check its permissions */
3524  nspOid = LookupCreationNamespace(newschema);
3525 
3526  objsMoved = new_object_addresses();
3527  oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3528  free_object_addresses(objsMoved);
3529 
3530  if (oldschema)
3531  *oldschema = oldNspOid;
3532 
3533  ObjectAddressSet(myself, TypeRelationId, typeOid);
3534 
3535  return myself;
3536 }
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2896
int errcode(int sqlerrcode)
Definition: elog.c:575
char get_typtype(Oid typid)
Definition: lsyscache.c:2379
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2081
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2352
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:3539
#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 3539 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().

3540 {
3541  Oid elemOid;
3542 
3543  /* check permissions on type */
3544  if (!pg_type_ownercheck(typeOid, GetUserId()))
3546 
3547  /* don't allow direct alteration of array types */
3548  elemOid = get_element_type(typeOid);
3549  if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3550  ereport(ERROR,
3551  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3552  errmsg("cannot alter array type %s",
3553  format_type_be(typeOid)),
3554  errhint("You can alter type %s, which will alter the array type as well.",
3555  format_type_be(elemOid))));
3556 
3557  /* and do the work */
3558  return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3559 }
int errhint(const char *fmt,...)
Definition: elog.c:987
Oid GetUserId(void)
Definition: miscinit.c:284
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2484
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2512
int errcode(int sqlerrcode)
Definition: elog.c:575
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3577
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:532
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 3577 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().

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

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

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

3408 {
3409  Relation rel;
3410  HeapTuple tup;
3411  Form_pg_type typTup;
3412 
3414 
3415  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3416  if (!HeapTupleIsValid(tup))
3417  elog(ERROR, "cache lookup failed for type %u", typeOid);
3418  typTup = (Form_pg_type) GETSTRUCT(tup);
3419 
3420  /*
3421  * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3422  * the pg_class entry properly. That will call back to
3423  * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3424  */
3425  if (typTup->typtype == TYPTYPE_COMPOSITE)
3426  ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3427  else
3428  AlterTypeOwnerInternal(typeOid, newOwnerId);
3429 
3430  /* Update owner dependency reference */
3431  if (hasDependEntry)
3432  changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3433 
3435 
3436  ReleaseSysCache(tup);
3438 }
#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:3447
#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
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:9922
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define elog
Definition: elog.h:219
void AlterTypeOwnerInternal ( Oid  typeOid,
Oid  newOwnerId 
)

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

3448 {
3449  Relation rel;
3450  HeapTuple tup;
3451  Form_pg_type typTup;
3452  Datum repl_val[Natts_pg_type];
3453  bool repl_null[Natts_pg_type];
3454  bool repl_repl[Natts_pg_type];
3455  Acl *newAcl;
3456  Datum aclDatum;
3457  bool isNull;
3458 
3460 
3461  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3462  if (!HeapTupleIsValid(tup))
3463  elog(ERROR, "cache lookup failed for type %u", typeOid);
3464  typTup = (Form_pg_type) GETSTRUCT(tup);
3465 
3466  memset(repl_null, false, sizeof(repl_null));
3467  memset(repl_repl, false, sizeof(repl_repl));
3468 
3469  repl_repl[Anum_pg_type_typowner - 1] = true;
3470  repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
3471 
3472  aclDatum = heap_getattr(tup,
3474  RelationGetDescr(rel),
3475  &isNull);
3476  /* Null ACLs do not require changes */
3477  if (!isNull)
3478  {
3479  newAcl = aclnewowner(DatumGetAclP(aclDatum),
3480  typTup->typowner, newOwnerId);
3481  repl_repl[Anum_pg_type_typacl - 1] = true;
3482  repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3483  }
3484 
3485  tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3486  repl_repl);
3487 
3488  CatalogTupleUpdate(rel, &tup->t_self, tup);
3489 
3490  /* If it has an array type, update that too */
3491  if (OidIsValid(typTup->typarray))
3492  AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
3493 
3494  /* Clean up */
3496 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define RelationGetDescr(relation)
Definition: rel.h:428
#define DatumGetAclP(X)
Definition: acl.h:121
#define PointerGetDatum(X)
Definition: postgres.h:562
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3447
#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:532
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:769
uintptr_t Datum
Definition: postgres.h:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define Natts_pg_type
Definition: pg_type.h:239
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Anum_pg_type_typacl
Definition: pg_type.h:269
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
#define elog
Definition: elog.h:219
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:794
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1052
#define Anum_pg_type_typowner
Definition: pg_type.h:242
Oid AssignTypeArrayOid ( void  )

Definition at line 2096 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 DefineDomain(), DefineEnum(), DefineRange(), DefineType(), and heap_create_with_catalog().

2097 {
2098  Oid type_array_oid;
2099 
2100  /* Use binary-upgrade override for pg_type.typarray? */
2101  if (IsBinaryUpgrade)
2102  {
2104  ereport(ERROR,
2105  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2106  errmsg("pg_type array OID value not set when in binary upgrade mode")));
2107 
2108  type_array_oid = binary_upgrade_next_array_pg_type_oid;
2110  }
2111  else
2112  {
2114 
2115  type_array_oid = GetNewOid(pg_type);
2116  heap_close(pg_type, AccessShareLock);
2117  }
2118 
2119  return type_array_oid;
2120 }
#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:532
bool IsBinaryUpgrade
Definition: globals.c:102
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
Oid GetNewOid(Relation relation)
Definition: catalog.c:289
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
Oid binary_upgrade_next_array_pg_type_oid
Definition: typecmds.c:86
int errmsg(const char *fmt,...)
Definition: elog.c:797
void checkDomainOwner ( HeapTuple  tup)

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

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

Definition at line 2137 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

2138 {
2139  CreateStmt *createStmt = makeNode(CreateStmt);
2140  Oid old_type_oid;
2141  Oid typeNamespace;
2142  ObjectAddress address;
2143 
2144  /*
2145  * now set the parameters for keys/inheritance etc. All of these are
2146  * uninteresting for composite types...
2147  */
2148  createStmt->relation = typevar;
2149  createStmt->tableElts = coldeflist;
2150  createStmt->inhRelations = NIL;
2151  createStmt->constraints = NIL;
2152  createStmt->options = NIL;
2153  createStmt->oncommit = ONCOMMIT_NOOP;
2154  createStmt->tablespacename = NULL;
2155  createStmt->if_not_exists = false;
2156 
2157  /*
2158  * Check for collision with an existing type name. If there is one and
2159  * it's an autogenerated array, we can rename it out of the way. This
2160  * check is here mainly to get a better error message about a "type"
2161  * instead of below about a "relation".
2162  */
2163  typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2164  NoLock, NULL);
2165  RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2166  old_type_oid =
2168  CStringGetDatum(createStmt->relation->relname),
2169  ObjectIdGetDatum(typeNamespace));
2170  if (OidIsValid(old_type_oid))
2171  {
2172  if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2173  ereport(ERROR,
2175  errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2176  }
2177 
2178  /*
2179  * Finally create the relation. This also creates the type.
2180  */
2181  DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2182  NULL);
2183 
2184  return address;
2185 }
RangeVar * relation
Definition: parsenodes.h:2003
#define NIL
Definition: pg_list.h:69
OnCommitAction oncommit
Definition: parsenodes.h:2012
List * inhRelations
Definition: parsenodes.h:2005
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:532
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition: namespace.c:615
#define RELKIND_COMPOSITE_TYPE
Definition: pg_class.h:166
#define GetSysCacheOid2(cacheId, key1, key2)
Definition: syscache.h:193
List * constraints
Definition: parsenodes.h:2010
bool if_not_exists
Definition: parsenodes.h:2014
char * relname
Definition: primnodes.h:68
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:833
#define NoLock
Definition: lockdefs.h:34
#define CStringGetDatum(X)
Definition: postgres.h:584
List * options
Definition: parsenodes.h:2011
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:504
#define ereport(elevel, rest)
Definition: elog.h:122
char * tablespacename
Definition: parsenodes.h:2013
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:508
#define InvalidOid
Definition: postgres_ext.h:36
List * tableElts
Definition: parsenodes.h:2004
#define makeNode(_type_)
Definition: nodes.h:558
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
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, AssignTypeArrayOid(), CreateDomainStmt::collClause, CollateClause::collname, CommandCounterIncrement(), CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_NOTNULL, CONSTR_NULL, CONSTR_PRIMARY, CONSTR_UNIQUE, CreateDomainStmt::constraints, Constraint::contype, cookDefault(), CStringGetDatum, deparse_expression(), domainAddConstraint(), CreateDomainStmt::domainname, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, format_type_be(), get_collation_oid(), get_namespace_name(), GETSTRUCT, GetSysCacheOid2, GetUserId(), HeapTupleGetOid, InvalidOid, Constraint::is_no_inherit, IsA, lfirst, list_length(), make_parsestate(), makeArrayTypeName(), moveArrayTypeName(), NIL, nodeTag, nodeToString(), ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, pfree(), pg_namespace_aclcheck(), pg_type_aclcheck(), QualifiedNameGetCreationNamespace(), Constraint::raw_expr, ReleaseSysCache(), SysCacheGetAttr(), TextDatumGetCString, TYPCATEGORY_ARRAY, TypeCreate(), CreateDomainStmt::typeName, TYPENAMENSP, TypeNameToString(), typenameType(), TYPEOID, TYPTYPE_BASE, TYPTYPE_DOMAIN, TYPTYPE_ENUM, and TYPTYPE_RANGE.

Referenced by ProcessUtilitySlow().

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

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

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

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

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

Definition at line 3220 of file typecmds.c.

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

Referenced by ExecRenameStmt().

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