PostgreSQL Source Code  git master
typecmds.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/tableam.h"
#include "access/xact.h"
#include "catalog/binary_upgrade.h"
#include "catalog/catalog.h"
#include "catalog/heap.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_am.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_range.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "commands/tablecmds.h"
#include "commands/typecmds.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "optimizer/optimizer.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/ruleutils.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
Include dependency graph for typecmds.c:

Go to the source code of this file.

Data Structures

struct  RelToCheck
 
struct  AlterTypeRecurseParams
 

Functions

static void makeRangeConstructors (const char *name, Oid namespace, Oid rangeOid, Oid subtype)
 
static Oid findTypeInputFunction (List *procname, Oid typeOid)
 
static Oid findTypeOutputFunction (List *procname, Oid typeOid)
 
static Oid findTypeReceiveFunction (List *procname, Oid typeOid)
 
static Oid findTypeSendFunction (List *procname, Oid typeOid)
 
static Oid findTypeTypmodinFunction (List *procname)
 
static Oid findTypeTypmodoutFunction (List *procname)
 
static Oid findTypeAnalyzeFunction (List *procname, Oid typeOid)
 
static Oid findRangeSubOpclass (List *opcname, Oid subtype)
 
static Oid findRangeCanonicalFunction (List *procname, Oid typeOid)
 
static Oid findRangeSubtypeDiffFunction (List *procname, Oid subtype)
 
static void validateDomainConstraint (Oid domainoid, char *ccbin)
 
static Listget_rels_with_domain (Oid domainOid, LOCKMODE lockmode)
 
static void checkEnumOwner (HeapTuple tup)
 
static char * domainAddConstraint (Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
 
static Nodereplace_domain_constraint_value (ParseState *pstate, ColumnRef *cref)
 
static void AlterTypeRecurse (Oid typeOid, HeapTuple tup, Relation catalog, AlterTypeRecurseParams *atparams)
 
ObjectAddress DefineType (ParseState *pstate, List *names, List *parameters)
 
void RemoveTypeById (Oid typeOid)
 
ObjectAddress DefineDomain (CreateDomainStmt *stmt)
 
ObjectAddress DefineEnum (CreateEnumStmt *stmt)
 
ObjectAddress AlterEnum (AlterEnumStmt *stmt)
 
ObjectAddress DefineRange (CreateRangeStmt *stmt)
 
Oid AssignTypeArrayOid (void)
 
ObjectAddress DefineCompositeType (RangeVar *typevar, List *coldeflist)
 
ObjectAddress AlterDomainDefault (List *names, Node *defaultRaw)
 
ObjectAddress AlterDomainNotNull (List *names, bool notNull)
 
ObjectAddress AlterDomainDropConstraint (List *names, const char *constrName, DropBehavior behavior, bool missing_ok)
 
ObjectAddress AlterDomainAddConstraint (List *names, Node *newConstraint, ObjectAddress *constrAddr)
 
ObjectAddress AlterDomainValidateConstraint (List *names, const char *constrName)
 
void checkDomainOwner (HeapTuple tup)
 
ObjectAddress RenameType (RenameStmt *stmt)
 
ObjectAddress AlterTypeOwner (List *names, Oid newOwnerId, ObjectType objecttype)
 
void AlterTypeOwner_oid (Oid typeOid, Oid newOwnerId, bool hasDependEntry)
 
void AlterTypeOwnerInternal (Oid typeOid, Oid newOwnerId)
 
ObjectAddress AlterTypeNamespace (List *names, const char *newschema, ObjectType objecttype, Oid *oldschema)
 
Oid AlterTypeNamespace_oid (Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
 
Oid AlterTypeNamespaceInternal (Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
 
ObjectAddress AlterType (AlterTypeStmt *stmt)
 

Variables

Oid binary_upgrade_next_array_pg_type_oid = InvalidOid
 

Function Documentation

◆ AlterDomainAddConstraint()

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

Definition at line 2471 of file typecmds.c.

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

Referenced by ATExecCmd(), and ProcessUtilitySlow().

2473 {
2474  TypeName *typename;
2475  Oid domainoid;
2476  Relation typrel;
2477  HeapTuple tup;
2478  Form_pg_type typTup;
2479  Constraint *constr;
2480  char *ccbin;
2481  ObjectAddress address;
2482 
2483  /* Make a TypeName so we can use standard type lookup machinery */
2484  typename = makeTypeNameFromNameList(names);
2485  domainoid = typenameTypeId(NULL, typename);
2486 
2487  /* Look up the domain in the type table */
2488  typrel = table_open(TypeRelationId, RowExclusiveLock);
2489 
2490  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2491  if (!HeapTupleIsValid(tup))
2492  elog(ERROR, "cache lookup failed for type %u", domainoid);
2493  typTup = (Form_pg_type) GETSTRUCT(tup);
2494 
2495  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2496  checkDomainOwner(tup);
2497 
2498  if (!IsA(newConstraint, Constraint))
2499  elog(ERROR, "unrecognized node type: %d",
2500  (int) nodeTag(newConstraint));
2501 
2502  constr = (Constraint *) newConstraint;
2503 
2504  switch (constr->contype)
2505  {
2506  case CONSTR_CHECK:
2507  /* processed below */
2508  break;
2509 
2510  case CONSTR_UNIQUE:
2511  ereport(ERROR,
2512  (errcode(ERRCODE_SYNTAX_ERROR),
2513  errmsg("unique constraints not possible for domains")));
2514  break;
2515 
2516  case CONSTR_PRIMARY:
2517  ereport(ERROR,
2518  (errcode(ERRCODE_SYNTAX_ERROR),
2519  errmsg("primary key constraints not possible for domains")));
2520  break;
2521 
2522  case CONSTR_EXCLUSION:
2523  ereport(ERROR,
2524  (errcode(ERRCODE_SYNTAX_ERROR),
2525  errmsg("exclusion constraints not possible for domains")));
2526  break;
2527 
2528  case CONSTR_FOREIGN:
2529  ereport(ERROR,
2530  (errcode(ERRCODE_SYNTAX_ERROR),
2531  errmsg("foreign key constraints not possible for domains")));
2532  break;
2533 
2536  case CONSTR_ATTR_DEFERRED:
2537  case CONSTR_ATTR_IMMEDIATE:
2538  ereport(ERROR,
2539  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2540  errmsg("specifying constraint deferrability not supported for domains")));
2541  break;
2542 
2543  default:
2544  elog(ERROR, "unrecognized constraint subtype: %d",
2545  (int) constr->contype);
2546  break;
2547  }
2548 
2549  /*
2550  * Since all other constraint types throw errors, this must be a check
2551  * constraint. First, process the constraint expression and add an entry
2552  * to pg_constraint.
2553  */
2554 
2555  ccbin = domainAddConstraint(domainoid, typTup->typnamespace,
2556  typTup->typbasetype, typTup->typtypmod,
2557  constr, NameStr(typTup->typname), constrAddr);
2558 
2559  /*
2560  * If requested to validate the constraint, test all values stored in the
2561  * attributes based on the domain the constraint is being added to.
2562  */
2563  if (!constr->skip_validation)
2564  validateDomainConstraint(domainoid, ccbin);
2565 
2566  /*
2567  * We must send out an sinval message for the domain, to ensure that any
2568  * dependent plans get rebuilt. Since this command doesn't change the
2569  * domain's pg_type row, that won't happen automatically; do it manually.
2570  */
2571  CacheInvalidateHeapTuple(typrel, tup, NULL);
2572 
2573  ObjectAddressSet(address, TypeRelationId, domainoid);
2574 
2575  /* Clean up */
2576  table_close(typrel, RowExclusiveLock);
2577 
2578  return address;
2579 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1114
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
static char * domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:2998
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
#define nodeTag(nodeptr)
Definition: nodes.h:534
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:2978
static void validateDomainConstraint(Oid domainoid, char *ccbin)
Definition: typecmds.c:2689
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:456
#define NameStr(name)
Definition: c.h:615
ConstrType contype
Definition: parsenodes.h:2152
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
bool skip_validation
Definition: parsenodes.h:2197
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ AlterDomainDefault()

ObjectAddress AlterDomainDefault ( List names,
Node defaultRaw 
)

Definition at line 2121 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

2122 {
2123  TypeName *typename;
2124  Oid domainoid;
2125  HeapTuple tup;
2126  ParseState *pstate;
2127  Relation rel;
2128  char *defaultValue;
2129  Node *defaultExpr = NULL; /* NULL if no default specified */
2130  Datum new_record[Natts_pg_type];
2131  bool new_record_nulls[Natts_pg_type];
2132  bool new_record_repl[Natts_pg_type];
2133  HeapTuple newtuple;
2134  Form_pg_type typTup;
2135  ObjectAddress address;
2136 
2137  /* Make a TypeName so we can use standard type lookup machinery */
2138  typename = makeTypeNameFromNameList(names);
2139  domainoid = typenameTypeId(NULL, typename);
2140 
2141  /* Look up the domain in the type table */
2142  rel = table_open(TypeRelationId, RowExclusiveLock);
2143 
2144  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2145  if (!HeapTupleIsValid(tup))
2146  elog(ERROR, "cache lookup failed for type %u", domainoid);
2147  typTup = (Form_pg_type) GETSTRUCT(tup);
2148 
2149  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2150  checkDomainOwner(tup);
2151 
2152  /* Setup new tuple */
2153  MemSet(new_record, (Datum) 0, sizeof(new_record));
2154  MemSet(new_record_nulls, false, sizeof(new_record_nulls));
2155  MemSet(new_record_repl, false, sizeof(new_record_repl));
2156 
2157  /* Store the new default into the tuple */
2158  if (defaultRaw)
2159  {
2160  /* Create a dummy ParseState for transformExpr */
2161  pstate = make_parsestate(NULL);
2162 
2163  /*
2164  * Cook the colDef->raw_expr into an expression. Note: Name is
2165  * strictly for error message
2166  */
2167  defaultExpr = cookDefault(pstate, defaultRaw,
2168  typTup->typbasetype,
2169  typTup->typtypmod,
2170  NameStr(typTup->typname),
2171  0);
2172 
2173  /*
2174  * If the expression is just a NULL constant, we treat the command
2175  * like ALTER ... DROP DEFAULT. (But see note for same test in
2176  * DefineDomain.)
2177  */
2178  if (defaultExpr == NULL ||
2179  (IsA(defaultExpr, Const) && ((Const *) defaultExpr)->constisnull))
2180  {
2181  /* Default is NULL, drop it */
2182  defaultExpr = NULL;
2183  new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2184  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2185  new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2186  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2187  }
2188  else
2189  {
2190  /*
2191  * Expression must be stored as a nodeToString result, but we also
2192  * require a valid textual representation (mainly to make life
2193  * easier for pg_dump).
2194  */
2195  defaultValue = deparse_expression(defaultExpr,
2196  NIL, false, false);
2197 
2198  /*
2199  * Form an updated tuple with the new default and write it back.
2200  */
2201  new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr));
2202 
2203  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2204  new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue);
2205  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2206  }
2207  }
2208  else
2209  {
2210  /* ALTER ... DROP DEFAULT */
2211  new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true;
2212  new_record_repl[Anum_pg_type_typdefaultbin - 1] = true;
2213  new_record_nulls[Anum_pg_type_typdefault - 1] = true;
2214  new_record_repl[Anum_pg_type_typdefault - 1] = true;
2215  }
2216 
2217  newtuple = heap_modify_tuple(tup, RelationGetDescr(rel),
2218  new_record, new_record_nulls,
2219  new_record_repl);
2220 
2221  CatalogTupleUpdate(rel, &tup->t_self, newtuple);
2222 
2223  /* Rebuild dependencies */
2224  GenerateTypeDependencies(newtuple,
2225  rel,
2226  defaultExpr,
2227  NULL, /* don't have typacl handy */
2228  0, /* relation kind is n/a */
2229  false, /* a domain isn't an implicit array */
2230  false, /* nor is it any kind of dependent type */
2231  true); /* We do need to rebuild dependencies */
2232 
2233  InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2234 
2235  ObjectAddressSet(address, TypeRelationId, domainoid);
2236 
2237  /* Clean up */
2239  heap_freetuple(newtuple);
2240 
2241  return address;
2242 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define RelationGetDescr(relation)
Definition: rel.h:482
Definition: nodes.h:529
#define MemSet(start, val, len)
Definition: c.h:971
Node * cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
Definition: heap.c:3003
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
uintptr_t Datum
Definition: postgres.h:367
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void GenerateTypeDependencies(HeapTuple typeTuple, Relation typeCatalog, Node *defaultExpr, void *typacl, char relationKind, bool isImplicitArray, bool isDependentType, bool rebuild)
Definition: pg_type.c:542
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3223
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:2978
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
#define elog(elevel,...)
Definition: elog.h:214
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:456
#define NameStr(name)
Definition: c.h:615
#define CStringGetTextDatum(s)
Definition: builtins.h:87
char * nodeToString(const void *obj)
Definition: outfuncs.c:4360
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ AlterDomainDropConstraint()

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

Definition at line 2372 of file typecmds.c.

References BTEqualStrategyNumber, CacheInvalidateHeapTuple(), checkDomainOwner(), ObjectAddress::classId, ConstraintRelidTypidNameIndexId, CStringGetDatum, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, InvalidOid, makeTypeNameFromNameList(), NOTICE, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, performDeletion(), RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TypeNameToString(), typenameTypeId(), and TYPEOID.

Referenced by ProcessUtilitySlow().

2374 {
2375  TypeName *typename;
2376  Oid domainoid;
2377  HeapTuple tup;
2378  Relation rel;
2379  Relation conrel;
2380  SysScanDesc conscan;
2381  ScanKeyData skey[3];
2382  HeapTuple contup;
2383  bool found = false;
2384  ObjectAddress address;
2385 
2386  /* Make a TypeName so we can use standard type lookup machinery */
2387  typename = makeTypeNameFromNameList(names);
2388  domainoid = typenameTypeId(NULL, typename);
2389 
2390  /* Look up the domain in the type table */
2391  rel = table_open(TypeRelationId, RowExclusiveLock);
2392 
2393  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2394  if (!HeapTupleIsValid(tup))
2395  elog(ERROR, "cache lookup failed for type %u", domainoid);
2396 
2397  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2398  checkDomainOwner(tup);
2399 
2400  /* Grab an appropriate lock on the pg_constraint relation */
2401  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
2402 
2403  /* Find and remove the target constraint */
2404  ScanKeyInit(&skey[0],
2405  Anum_pg_constraint_conrelid,
2406  BTEqualStrategyNumber, F_OIDEQ,
2408  ScanKeyInit(&skey[1],
2409  Anum_pg_constraint_contypid,
2410  BTEqualStrategyNumber, F_OIDEQ,
2411  ObjectIdGetDatum(domainoid));
2412  ScanKeyInit(&skey[2],
2413  Anum_pg_constraint_conname,
2414  BTEqualStrategyNumber, F_NAMEEQ,
2415  CStringGetDatum(constrName));
2416 
2417  conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
2418  NULL, 3, skey);
2419 
2420  /* There can be at most one matching row */
2421  if ((contup = systable_getnext(conscan)) != NULL)
2422  {
2423  ObjectAddress conobj;
2424 
2425  conobj.classId = ConstraintRelationId;
2426  conobj.objectId = ((Form_pg_constraint) GETSTRUCT(contup))->oid;
2427  conobj.objectSubId = 0;
2428 
2429  performDeletion(&conobj, behavior, 0);
2430  found = true;
2431  }
2432 
2433  /* Clean up after the scan */
2434  systable_endscan(conscan);
2435  table_close(conrel, RowExclusiveLock);
2436 
2437  if (!found)
2438  {
2439  if (!missing_ok)
2440  ereport(ERROR,
2441  (errcode(ERRCODE_UNDEFINED_OBJECT),
2442  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2443  constrName, TypeNameToString(typename))));
2444  else
2445  ereport(NOTICE,
2446  (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping",
2447  constrName, TypeNameToString(typename))));
2448  }
2449 
2450  /*
2451  * We must send out an sinval message for the domain, to ensure that any
2452  * dependent plans get rebuilt. Since this command doesn't change the
2453  * domain's pg_type row, that won't happen automatically; do it manually.
2454  */
2455  CacheInvalidateHeapTuple(rel, tup, NULL);
2456 
2457  ObjectAddressSet(address, TypeRelationId, domainoid);
2458 
2459  /* Clean up */
2461 
2462  return address;
2463 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1114
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:476
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:312
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define NOTICE
Definition: elog.h:37
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:2978
#define ConstraintRelidTypidNameIndexId
Definition: indexing.h:128
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:456
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ AlterDomainNotNull()

ObjectAddress AlterDomainNotNull ( List names,
bool  notNull 
)

Definition at line 2252 of file typecmds.c.

References attnum, RelToCheck::atts, CatalogTupleUpdate(), checkDomainOwner(), elog, ereport, errcode(), errmsg(), ERROR, errtablecol(), ExecDropSingleTupleTableSlot(), ForwardScanDirection, get_rels_with_domain(), GetLatestSnapshot(), GETSTRUCT, heap_freetuple(), HeapTupleIsValid, i, InvalidObjectAddress, InvokeObjectPostAlterHook, lfirst, makeTypeNameFromNameList(), NameStr, RelToCheck::natts, NoLock, ObjectAddressSet, ObjectIdGetDatum, RegisterSnapshot(), RelToCheck::rel, RelationGetDescr, RelationGetRelationName, RowExclusiveLock, SearchSysCacheCopy1, ShareLock, slot_attisnull(), HeapTupleData::t_self, table_beginscan(), table_close(), table_endscan(), table_open(), table_scan_getnextslot(), table_slot_create(), TupleDescAttr, typenameTypeId(), TYPEOID, and UnregisterSnapshot().

Referenced by ProcessUtilitySlow().

2253 {
2254  TypeName *typename;
2255  Oid domainoid;
2256  Relation typrel;
2257  HeapTuple tup;
2258  Form_pg_type typTup;
2260 
2261  /* Make a TypeName so we can use standard type lookup machinery */
2262  typename = makeTypeNameFromNameList(names);
2263  domainoid = typenameTypeId(NULL, typename);
2264 
2265  /* Look up the domain in the type table */
2266  typrel = table_open(TypeRelationId, RowExclusiveLock);
2267 
2268  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid));
2269  if (!HeapTupleIsValid(tup))
2270  elog(ERROR, "cache lookup failed for type %u", domainoid);
2271  typTup = (Form_pg_type) GETSTRUCT(tup);
2272 
2273  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2274  checkDomainOwner(tup);
2275 
2276  /* Is the domain already set to the desired constraint? */
2277  if (typTup->typnotnull == notNull)
2278  {
2279  table_close(typrel, RowExclusiveLock);
2280  return address;
2281  }
2282 
2283  /* Adding a NOT NULL constraint requires checking existing columns */
2284  if (notNull)
2285  {
2286  List *rels;
2287  ListCell *rt;
2288 
2289  /* Fetch relation list with attributes based on this domain */
2290  /* ShareLock is sufficient to prevent concurrent data changes */
2291 
2292  rels = get_rels_with_domain(domainoid, ShareLock);
2293 
2294  foreach(rt, rels)
2295  {
2296  RelToCheck *rtc = (RelToCheck *) lfirst(rt);
2297  Relation testrel = rtc->rel;
2298  TupleDesc tupdesc = RelationGetDescr(testrel);
2299  TupleTableSlot *slot;
2300  TableScanDesc scan;
2301  Snapshot snapshot;
2302 
2303  /* Scan all tuples in this relation */
2304  snapshot = RegisterSnapshot(GetLatestSnapshot());
2305  scan = table_beginscan(testrel, snapshot, 0, NULL);
2306  slot = table_slot_create(testrel, NULL);
2307  while (table_scan_getnextslot(scan, ForwardScanDirection, slot))
2308  {
2309  int i;
2310 
2311  /* Test attributes that are of the domain */
2312  for (i = 0; i < rtc->natts; i++)
2313  {
2314  int attnum = rtc->atts[i];
2315  Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1);
2316 
2317  if (slot_attisnull(slot, attnum))
2318  {
2319  /*
2320  * In principle the auxiliary information for this
2321  * error should be errdatatype(), but errtablecol()
2322  * seems considerably more useful in practice. Since
2323  * this code only executes in an ALTER DOMAIN command,
2324  * the client should already know which domain is in
2325  * question.
2326  */
2327  ereport(ERROR,
2328  (errcode(ERRCODE_NOT_NULL_VIOLATION),
2329  errmsg("column \"%s\" of table \"%s\" contains null values",
2330  NameStr(attr->attname),
2331  RelationGetRelationName(testrel)),
2332  errtablecol(testrel, attnum)));
2333  }
2334  }
2335  }
2337  table_endscan(scan);
2338  UnregisterSnapshot(snapshot);
2339 
2340  /* Close each rel after processing, but keep lock */
2341  table_close(testrel, NoLock);
2342  }
2343  }
2344 
2345  /*
2346  * Okay to update pg_type row. We can scribble on typTup because it's a
2347  * copy.
2348  */
2349  typTup->typnotnull = notNull;
2350 
2351  CatalogTupleUpdate(typrel, &tup->t_self, tup);
2352 
2353  InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
2354 
2355  ObjectAddressSet(address, TypeRelationId, domainoid);
2356 
2357  /* Clean up */
2358  heap_freetuple(tup);
2359  table_close(typrel, RowExclusiveLock);
2360 
2361  return address;
2362 }
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:77
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int * atts
Definition: typecmds.c:83
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:865
#define RelationGetDescr(relation)
Definition: rel.h:482
Relation rel
Definition: typecmds.c:81
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int errcode(int sqlerrcode)
Definition: elog.c:610
static bool table_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition: tableam.h:903
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
static TableScanDesc table_beginscan(Relation rel, Snapshot snapshot, int nkeys, struct ScanKeyData *key)
Definition: tableam.h:754
ItemPointerData t_self
Definition: htup.h:65
#define NoLock
Definition: lockdefs.h:34
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
Definition: execTuples.c:1224
#define RowExclusiveLock
Definition: lockdefs.h:38
#define RelationGetRelationName(relation)
Definition: rel.h:490
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:193
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:907
static List * get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
Definition: typecmds.c:2809
int16 attnum
Definition: pg_attribute.h:79
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:190
int errtablecol(Relation rel, int attnum)
Definition: relcache.c:5507
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
Snapshot GetLatestSnapshot(void)
Definition: snapmgr.c:381
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:2978
static void table_endscan(TableScanDesc scan)
Definition: tableam.h:862
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
#define ShareLock
Definition: lockdefs.h:41
int i
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:456
#define NameStr(name)
Definition: c.h:615
static bool slot_attisnull(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:367
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
int natts
Definition: typecmds.c:82

◆ AlterDomainValidateConstraint()

ObjectAddress AlterDomainValidateConstraint ( List names,
const char *  constrName 
)

Definition at line 2587 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

2588 {
2589  TypeName *typename;
2590  Oid domainoid;
2591  Relation typrel;
2592  Relation conrel;
2593  HeapTuple tup;
2594  Form_pg_constraint con;
2595  Form_pg_constraint copy_con;
2596  char *conbin;
2597  SysScanDesc scan;
2598  Datum val;
2599  bool isnull;
2600  HeapTuple tuple;
2601  HeapTuple copyTuple;
2602  ScanKeyData skey[3];
2603  ObjectAddress address;
2604 
2605  /* Make a TypeName so we can use standard type lookup machinery */
2606  typename = makeTypeNameFromNameList(names);
2607  domainoid = typenameTypeId(NULL, typename);
2608 
2609  /* Look up the domain in the type table */
2610  typrel = table_open(TypeRelationId, AccessShareLock);
2611 
2612  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid));
2613  if (!HeapTupleIsValid(tup))
2614  elog(ERROR, "cache lookup failed for type %u", domainoid);
2615 
2616  /* Check it's a domain and check user has permission for ALTER DOMAIN */
2617  checkDomainOwner(tup);
2618 
2619  /*
2620  * Find and check the target constraint
2621  */
2622  conrel = table_open(ConstraintRelationId, RowExclusiveLock);
2623 
2624  ScanKeyInit(&skey[0],
2625  Anum_pg_constraint_conrelid,
2626  BTEqualStrategyNumber, F_OIDEQ,
2628  ScanKeyInit(&skey[1],
2629  Anum_pg_constraint_contypid,
2630  BTEqualStrategyNumber, F_OIDEQ,
2631  ObjectIdGetDatum(domainoid));
2632  ScanKeyInit(&skey[2],
2633  Anum_pg_constraint_conname,
2634  BTEqualStrategyNumber, F_NAMEEQ,
2635  CStringGetDatum(constrName));
2636 
2638  NULL, 3, skey);
2639 
2640  /* There can be at most one matching row */
2641  if (!HeapTupleIsValid(tuple = systable_getnext(scan)))
2642  ereport(ERROR,
2643  (errcode(ERRCODE_UNDEFINED_OBJECT),
2644  errmsg("constraint \"%s\" of domain \"%s\" does not exist",
2645  constrName, TypeNameToString(typename))));
2646 
2647  con = (Form_pg_constraint) GETSTRUCT(tuple);
2648  if (con->contype != CONSTRAINT_CHECK)
2649  ereport(ERROR,
2650  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2651  errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint",
2652  constrName, TypeNameToString(typename))));
2653 
2654  val = SysCacheGetAttr(CONSTROID, tuple,
2655  Anum_pg_constraint_conbin,
2656  &isnull);
2657  if (isnull)
2658  elog(ERROR, "null conbin for constraint %u",
2659  con->oid);
2660  conbin = TextDatumGetCString(val);
2661 
2662  validateDomainConstraint(domainoid, conbin);
2663 
2664  /*
2665  * Now update the catalog, while we have the door open.
2666  */
2667  copyTuple = heap_copytuple(tuple);
2668  copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple);
2669  copy_con->convalidated = true;
2670  CatalogTupleUpdate(conrel, &copyTuple->t_self, copyTuple);
2671 
2672  InvokeObjectPostAlterHook(ConstraintRelationId, con->oid, 0);
2673 
2674  ObjectAddressSet(address, TypeRelationId, domainoid);
2675 
2676  heap_freetuple(copyTuple);
2677 
2678  systable_endscan(scan);
2679 
2680  table_close(typrel, AccessShareLock);
2681  table_close(conrel, RowExclusiveLock);
2682 
2683  ReleaseSysCache(tup);
2684 
2685  return address;
2686 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:476
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:610
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
#define TextDatumGetCString(d)
Definition: builtins.h:88
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1377
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void checkDomainOwner(HeapTuple tup)
Definition: typecmds.c:2978
static void validateDomainConstraint(Oid domainoid, char *ccbin)
Definition: typecmds.c:2689
#define ConstraintRelidTypidNameIndexId
Definition: indexing.h:128
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:456
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
long val
Definition: informix.c:664
#define BTEqualStrategyNumber
Definition: stratnum.h:31
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ AlterEnum()

ObjectAddress AlterEnum ( AlterEnumStmt stmt)

Definition at line 1214 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

1215 {
1216  Oid enum_type_oid;
1217  TypeName *typename;
1218  HeapTuple tup;
1219  ObjectAddress address;
1220 
1221  /* Make a TypeName so we can use standard type lookup machinery */
1222  typename = makeTypeNameFromNameList(stmt->typeName);
1223  enum_type_oid = typenameTypeId(NULL, typename);
1224 
1225  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
1226  if (!HeapTupleIsValid(tup))
1227  elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
1228 
1229  /* Check it's an enum and check user has permission to ALTER the enum */
1230  checkEnumOwner(tup);
1231 
1232  ReleaseSysCache(tup);
1233 
1234  if (stmt->oldVal)
1235  {
1236  /* Rename an existing label */
1237  RenameEnumLabel(enum_type_oid, stmt->oldVal, stmt->newVal);
1238  }
1239  else
1240  {
1241  /* Add a new label */
1242  AddEnumLabel(enum_type_oid, stmt->newVal,
1243  stmt->newValNeighbor, stmt->newValIsAfter,
1244  stmt->skipIfNewValExists);
1245  }
1246 
1247  InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
1248 
1249  ObjectAddressSet(address, TypeRelationId, enum_type_oid);
1250 
1251  return address;
1252 }
unsigned int Oid
Definition: postgres_ext.h:31
char * newValNeighbor
Definition: parsenodes.h:3109
static void checkEnumOwner(HeapTuple tup)
Definition: typecmds.c:1262
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
List * typeName
Definition: parsenodes.h:3106
void AddEnumLabel(Oid enumTypeOid, const char *newVal, const char *neighbor, bool newValIsAfter, bool skipIfExists)
Definition: pg_enum.c:208
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
void RenameEnumLabel(Oid enumTypeOid, const char *oldVal, const char *newVal)
Definition: pg_enum.c:508
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
bool skipIfNewValExists
Definition: parsenodes.h:3111
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
bool newValIsAfter
Definition: parsenodes.h:3110
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
#define elog(elevel,...)
Definition: elog.h:214
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:456
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ AlterType()

ObjectAddress AlterType ( AlterTypeStmt stmt)

Definition at line 3653 of file typecmds.c.

References aclcheck_error_type(), ACLCHECK_NOT_OWNER, AlterTypeRecurse(), AlterTypeRecurseParams::analyzeOid, DefElem::arg, defGetQualifiedName(), defGetString(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, findTypeAnalyzeFunction(), findTypeReceiveFunction(), findTypeSendFunction(), findTypeTypmodinFunction(), findTypeTypmodoutFunction(), format_type_be(), get_array_type(), GETSTRUCT, GetUserId(), InvalidOid, lfirst, makeTypeNameFromNameList(), ObjectAddressSet, OidIsValid, AlterTypeStmt::options, pg_strcasecmp(), pg_type_ownercheck(), AlterTypeRecurseParams::receiveOid, ReleaseSysCache(), RowExclusiveLock, AlterTypeRecurseParams::sendOid, AlterTypeRecurseParams::storage, superuser(), table_close(), table_open(), AlterTypeStmt::typeName, typenameType(), typeTypeId(), AlterTypeRecurseParams::typmodinOid, AlterTypeRecurseParams::typmodoutOid, AlterTypeRecurseParams::updateAnalyze, AlterTypeRecurseParams::updateReceive, AlterTypeRecurseParams::updateSend, AlterTypeRecurseParams::updateStorage, AlterTypeRecurseParams::updateTypmodin, and AlterTypeRecurseParams::updateTypmodout.

Referenced by ProcessUtilitySlow().

3654 {
3655  ObjectAddress address;
3656  Relation catalog;
3657  TypeName *typename;
3658  HeapTuple tup;
3659  Oid typeOid;
3660  Form_pg_type typForm;
3661  bool requireSuper = false;
3662  AlterTypeRecurseParams atparams;
3663  ListCell *pl;
3664 
3665  catalog = table_open(TypeRelationId, RowExclusiveLock);
3666 
3667  /* Make a TypeName so we can use standard type lookup machinery */
3668  typename = makeTypeNameFromNameList(stmt->typeName);
3669  tup = typenameType(NULL, typename, NULL);
3670 
3671  typeOid = typeTypeId(tup);
3672  typForm = (Form_pg_type) GETSTRUCT(tup);
3673 
3674  /* Process options */
3675  memset(&atparams, 0, sizeof(atparams));
3676  foreach(pl, stmt->options)
3677  {
3678  DefElem *defel = (DefElem *) lfirst(pl);
3679 
3680  if (strcmp(defel->defname, "storage") == 0)
3681  {
3682  char *a = defGetString(defel);
3683 
3684  if (pg_strcasecmp(a, "plain") == 0)
3685  atparams.storage = TYPSTORAGE_PLAIN;
3686  else if (pg_strcasecmp(a, "external") == 0)
3687  atparams.storage = TYPSTORAGE_EXTERNAL;
3688  else if (pg_strcasecmp(a, "extended") == 0)
3689  atparams.storage = TYPSTORAGE_EXTENDED;
3690  else if (pg_strcasecmp(a, "main") == 0)
3691  atparams.storage = TYPSTORAGE_MAIN;
3692  else
3693  ereport(ERROR,
3694  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3695  errmsg("storage \"%s\" not recognized", a)));
3696 
3697  /*
3698  * Validate the storage request. If the type isn't varlena, it
3699  * certainly doesn't support non-PLAIN storage.
3700  */
3701  if (atparams.storage != TYPSTORAGE_PLAIN && typForm->typlen != -1)
3702  ereport(ERROR,
3703  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3704  errmsg("fixed-size types must have storage PLAIN")));
3705 
3706  /*
3707  * Switching from PLAIN to non-PLAIN is allowed, but it requires
3708  * superuser, since we can't validate that the type's C functions
3709  * will support it. Switching from non-PLAIN to PLAIN is
3710  * disallowed outright, because it's not practical to ensure that
3711  * no tables have toasted values of the type. Switching among
3712  * different non-PLAIN settings is OK, since it just constitutes a
3713  * change in the strategy requested for columns created in the
3714  * future.
3715  */
3716  if (atparams.storage != TYPSTORAGE_PLAIN &&
3717  typForm->typstorage == TYPSTORAGE_PLAIN)
3718  requireSuper = true;
3719  else if (atparams.storage == TYPSTORAGE_PLAIN &&
3720  typForm->typstorage != TYPSTORAGE_PLAIN)
3721  ereport(ERROR,
3722  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3723  errmsg("cannot change type's storage to PLAIN")));
3724 
3725  atparams.updateStorage = true;
3726  }
3727  else if (strcmp(defel->defname, "receive") == 0)
3728  {
3729  if (defel->arg != NULL)
3730  atparams.receiveOid =
3732  typeOid);
3733  else
3734  atparams.receiveOid = InvalidOid; /* NONE, remove function */
3735  atparams.updateReceive = true;
3736  /* Replacing an I/O function requires superuser. */
3737  requireSuper = true;
3738  }
3739  else if (strcmp(defel->defname, "send") == 0)
3740  {
3741  if (defel->arg != NULL)
3742  atparams.sendOid =
3744  typeOid);
3745  else
3746  atparams.sendOid = InvalidOid; /* NONE, remove function */
3747  atparams.updateSend = true;
3748  /* Replacing an I/O function requires superuser. */
3749  requireSuper = true;
3750  }
3751  else if (strcmp(defel->defname, "typmod_in") == 0)
3752  {
3753  if (defel->arg != NULL)
3754  atparams.typmodinOid =
3756  else
3757  atparams.typmodinOid = InvalidOid; /* NONE, remove function */
3758  atparams.updateTypmodin = true;
3759  /* Replacing an I/O function requires superuser. */
3760  requireSuper = true;
3761  }
3762  else if (strcmp(defel->defname, "typmod_out") == 0)
3763  {
3764  if (defel->arg != NULL)
3765  atparams.typmodoutOid =
3767  else
3768  atparams.typmodoutOid = InvalidOid; /* NONE, remove function */
3769  atparams.updateTypmodout = true;
3770  /* Replacing an I/O function requires superuser. */
3771  requireSuper = true;
3772  }
3773  else if (strcmp(defel->defname, "analyze") == 0)
3774  {
3775  if (defel->arg != NULL)
3776  atparams.analyzeOid =
3778  typeOid);
3779  else
3780  atparams.analyzeOid = InvalidOid; /* NONE, remove function */
3781  atparams.updateAnalyze = true;
3782  /* Replacing an analyze function requires superuser. */
3783  requireSuper = true;
3784  }
3785 
3786  /*
3787  * The rest of the options that CREATE accepts cannot be changed.
3788  * Check for them so that we can give a meaningful error message.
3789  */
3790  else if (strcmp(defel->defname, "input") == 0 ||
3791  strcmp(defel->defname, "output") == 0 ||
3792  strcmp(defel->defname, "internallength") == 0 ||
3793  strcmp(defel->defname, "passedbyvalue") == 0 ||
3794  strcmp(defel->defname, "alignment") == 0 ||
3795  strcmp(defel->defname, "like") == 0 ||
3796  strcmp(defel->defname, "category") == 0 ||
3797  strcmp(defel->defname, "preferred") == 0 ||
3798  strcmp(defel->defname, "default") == 0 ||
3799  strcmp(defel->defname, "element") == 0 ||
3800  strcmp(defel->defname, "delimiter") == 0 ||
3801  strcmp(defel->defname, "collatable") == 0)
3802  ereport(ERROR,
3803  (errcode(ERRCODE_SYNTAX_ERROR),
3804  errmsg("type attribute \"%s\" cannot be changed",
3805  defel->defname)));
3806  else
3807  ereport(ERROR,
3808  (errcode(ERRCODE_SYNTAX_ERROR),
3809  errmsg("type attribute \"%s\" not recognized",
3810  defel->defname)));
3811  }
3812 
3813  /*
3814  * Permissions check. Require superuser if we decided the command
3815  * requires that, else must own the type.
3816  */
3817  if (requireSuper)
3818  {
3819  if (!superuser())
3820  ereport(ERROR,
3821  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3822  errmsg("must be superuser to alter a type")));
3823  }
3824  else
3825  {
3826  if (!pg_type_ownercheck(typeOid, GetUserId()))
3828  }
3829 
3830  /*
3831  * We disallow all forms of ALTER TYPE SET on types that aren't plain base
3832  * types. It would for example be highly unsafe, not to mention
3833  * pointless, to change the send/receive functions for a composite type.
3834  * Moreover, pg_dump has no support for changing these properties on
3835  * non-base types. We might weaken this someday, but not now.
3836  *
3837  * Note: if you weaken this enough to allow composite types, be sure to
3838  * adjust the GenerateTypeDependencies call in AlterTypeRecurse.
3839  */
3840  if (typForm->typtype != TYPTYPE_BASE)
3841  ereport(ERROR,
3842  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3843  errmsg("%s is not a base type",
3844  format_type_be(typeOid))));
3845 
3846  /*
3847  * For the same reasons, don't allow direct alteration of array types.
3848  */
3849  if (OidIsValid(typForm->typelem) &&
3850  get_array_type(typForm->typelem) == typeOid)
3851  ereport(ERROR,
3852  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3853  errmsg("%s is not a base type",
3854  format_type_be(typeOid))));
3855 
3856  /* OK, recursively update this type and any domains over it */
3857  AlterTypeRecurse(typeOid, tup, catalog, &atparams);
3858 
3859  /* Clean up */
3860  ReleaseSysCache(tup);
3861 
3862  table_close(catalog, RowExclusiveLock);
3863 
3864  ObjectAddressSet(address, TypeRelationId, typeOid);
3865 
3866  return address;
3867 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
static Oid findTypeReceiveFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1712
Oid GetUserId(void)
Definition: miscinit.c:448
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2664
static Oid findTypeTypmodinFunction(List *procname)
Definition: typecmds.c:1790
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
List * typeName
Definition: parsenodes.h:2987
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
unsigned int Oid
Definition: postgres_ext.h:31
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4713
#define OidIsValid(objectId)
Definition: c.h:644
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3607
#define ERROR
Definition: elog.h:43
char * defGetString(DefElem *def)
Definition: define.c:49
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1858
#define RowExclusiveLock
Definition: lockdefs.h:38
static Oid findTypeTypmodoutFunction(List *procname)
Definition: typecmds.c:1824
Node * arg
Definition: parsenodes.h:733
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
List * options
Definition: parsenodes.h:2988
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:190
List * defGetQualifiedName(DefElem *def)
Definition: define.c:223
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
int errmsg(const char *fmt,...)
Definition: elog.c:824
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:456
char * defname
Definition: parsenodes.h:732
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Oid typeTypeId(Type tp)
Definition: parse_type.c:588
static void AlterTypeRecurse(Oid typeOid, HeapTuple tup, Relation catalog, AlterTypeRecurseParams *atparams)
Definition: typecmds.c:3891
static Oid findTypeSendFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1755

◆ AlterTypeNamespace()

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

Definition at line 3435 of file typecmds.c.

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

Referenced by ExecAlterObjectSchemaStmt().

3437 {
3438  TypeName *typename;
3439  Oid typeOid;
3440  Oid nspOid;
3441  Oid oldNspOid;
3442  ObjectAddresses *objsMoved;
3443  ObjectAddress myself;
3444 
3445  /* Make a TypeName so we can use standard type lookup machinery */
3446  typename = makeTypeNameFromNameList(names);
3447  typeOid = typenameTypeId(NULL, typename);
3448 
3449  /* Don't allow ALTER DOMAIN on a type */
3450  if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN)
3451  ereport(ERROR,
3452  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3453  errmsg("%s is not a domain",
3454  format_type_be(typeOid))));
3455 
3456  /* get schema OID and check its permissions */
3457  nspOid = LookupCreationNamespace(newschema);
3458 
3459  objsMoved = new_object_addresses();
3460  oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
3461  free_object_addresses(objsMoved);
3462 
3463  if (oldschema)
3464  *oldschema = oldNspOid;
3465 
3466  ObjectAddressSet(myself, TypeRelationId, typeOid);
3467 
3468  return myself;
3469 }
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2936
int errcode(int sqlerrcode)
Definition: elog.c:610
char get_typtype(Oid typid)
Definition: lsyscache.c:2517
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2410
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2705
unsigned int Oid
Definition: postgres_ext.h:31
#define ERROR
Definition: elog.h:43
Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: typecmds.c:3472
#define ereport(elevel,...)
Definition: elog.h:144
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
int errmsg(const char *fmt,...)
Definition: elog.c:824
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:456
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ AlterTypeNamespace_oid()

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

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

3473 {
3474  Oid elemOid;
3475 
3476  /* check permissions on type */
3477  if (!pg_type_ownercheck(typeOid, GetUserId()))
3479 
3480  /* don't allow direct alteration of array types */
3481  elemOid = get_element_type(typeOid);
3482  if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid)
3483  ereport(ERROR,
3484  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3485  errmsg("cannot alter array type %s",
3486  format_type_be(typeOid)),
3487  errhint("You can alter type %s, which will alter the array type as well.",
3488  format_type_be(elemOid))));
3489 
3490  /* and do the work */
3491  return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved);
3492 }
int errhint(const char *fmt,...)
Definition: elog.c:1071
Oid GetUserId(void)
Definition: miscinit.c:448
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2636
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2664
int errcode(int sqlerrcode)
Definition: elog.c:610
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3510
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
unsigned int Oid
Definition: postgres_ext.h:31
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4713
#define OidIsValid(objectId)
Definition: c.h:644
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3607
#define ERROR
Definition: elog.h:43
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ AlterTypeNamespaceInternal()

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

Definition at line 3510 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_freetuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHook, NameGetDatum, NameStr, object_address_present(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, RowExclusiveLock, SearchSysCacheCopy1, SearchSysCacheExists2, HeapTupleData::t_self, table_close(), table_open(), TYPENAMENSP, and TYPEOID.

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

3514 {
3515  Relation rel;
3516  HeapTuple tup;
3517  Form_pg_type typform;
3518  Oid oldNspOid;
3519  Oid arrayOid;
3520  bool isCompositeType;
3521  ObjectAddress thisobj;
3522 
3523  /*
3524  * Make sure we haven't moved this object previously.
3525  */
3526  thisobj.classId = TypeRelationId;
3527  thisobj.objectId = typeOid;
3528  thisobj.objectSubId = 0;
3529 
3530  if (object_address_present(&thisobj, objsMoved))
3531  return InvalidOid;
3532 
3533  rel = table_open(TypeRelationId, RowExclusiveLock);
3534 
3535  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3536  if (!HeapTupleIsValid(tup))
3537  elog(ERROR, "cache lookup failed for type %u", typeOid);
3538  typform = (Form_pg_type) GETSTRUCT(tup);
3539 
3540  oldNspOid = typform->typnamespace;
3541  arrayOid = typform->typarray;
3542 
3543  /* If the type is already there, we scan skip these next few checks. */
3544  if (oldNspOid != nspOid)
3545  {
3546  /* common checks on switching namespaces */
3547  CheckSetNamespace(oldNspOid, nspOid);
3548 
3549  /* check for duplicate name (more friendly than unique-index failure) */
3551  NameGetDatum(&typform->typname),
3552  ObjectIdGetDatum(nspOid)))
3553  ereport(ERROR,
3555  errmsg("type \"%s\" already exists in schema \"%s\"",
3556  NameStr(typform->typname),
3557  get_namespace_name(nspOid))));
3558  }
3559 
3560  /* Detect whether type is a composite type (but not a table rowtype) */
3561  isCompositeType =
3562  (typform->typtype == TYPTYPE_COMPOSITE &&
3563  get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
3564 
3565  /* Enforce not-table-type if requested */
3566  if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
3567  errorOnTableType)
3568  ereport(ERROR,
3569  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3570  errmsg("%s is a table's row type",
3571  format_type_be(typeOid)),
3572  errhint("Use ALTER TABLE instead.")));
3573 
3574  if (oldNspOid != nspOid)
3575  {
3576  /* OK, modify the pg_type row */
3577 
3578  /* tup is a copy, so we can scribble directly on it */
3579  typform->typnamespace = nspOid;
3580 
3581  CatalogTupleUpdate(rel, &tup->t_self, tup);
3582  }
3583 
3584  /*
3585  * Composite types have pg_class entries.
3586  *
3587  * We need to modify the pg_class tuple as well to reflect the change of
3588  * schema.
3589  */
3590  if (isCompositeType)
3591  {
3592  Relation classRel;
3593 
3594  classRel = table_open(RelationRelationId, RowExclusiveLock);
3595 
3596  AlterRelationNamespaceInternal(classRel, typform->typrelid,
3597  oldNspOid, nspOid,
3598  false, objsMoved);
3599 
3600  table_close(classRel, RowExclusiveLock);
3601 
3602  /*
3603  * Check for constraints associated with the composite type (we don't
3604  * currently support this, but probably will someday).
3605  */
3606  AlterConstraintNamespaces(typform->typrelid, oldNspOid,
3607  nspOid, false, objsMoved);
3608  }
3609  else
3610  {
3611  /* If it's a domain, it might have constraints */
3612  if (typform->typtype == TYPTYPE_DOMAIN)
3613  AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true,
3614  objsMoved);
3615  }
3616 
3617  /*
3618  * Update dependency on schema, if any --- a table rowtype has not got
3619  * one, and neither does an implicit array.
3620  */
3621  if (oldNspOid != nspOid &&
3622  (isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
3623  !isImplicitArray)
3624  if (changeDependencyFor(TypeRelationId, typeOid,
3625  NamespaceRelationId, oldNspOid, nspOid) != 1)
3626  elog(ERROR, "failed to change schema dependency for type %s",
3627  format_type_be(typeOid));
3628 
3629  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3630 
3631  heap_freetuple(tup);
3632 
3634 
3635  add_exact_object_address(&thisobj, objsMoved);
3636 
3637  /* Recursively alter the associated array type, if any */
3638  if (OidIsValid(arrayOid))
3639  AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved);
3640 
3641  return oldNspOid;
3642 }
#define NameGetDatum(X)
Definition: postgres.h:595
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int errhint(const char *fmt,...)
Definition: elog.c:1071
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1915
bool object_address_present(const ObjectAddress *object, const ObjectAddresses *addrs)
Definition: dependency.c:2525
int errcode(int sqlerrcode)
Definition: elog.c:610
Oid AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool isImplicitArray, bool errorOnTableType, ObjectAddresses *objsMoved)
Definition: typecmds.c:3510
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2465
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved)
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
void CheckSetNamespace(Oid oldNspOid, Oid nspOid)
Definition: namespace.c:2967
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
#define SearchSysCacheExists2(cacheId, key1, key2)
Definition: syscache.h:185
void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry, ObjectAddresses *objsMoved)
Definition: tablecmds.c:15037
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
int errmsg(const char *fmt,...)
Definition: elog.c:824
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:346
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:615
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31

◆ AlterTypeOwner()

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

Definition at line 3231 of file typecmds.c.

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

Referenced by ExecAlterOwnerStmt().

3232 {
3233  TypeName *typename;
3234  Oid typeOid;
3235  Relation rel;
3236  HeapTuple tup;
3237  HeapTuple newtup;
3238  Form_pg_type typTup;
3239  AclResult aclresult;
3240  ObjectAddress address;
3241 
3242  rel = table_open(TypeRelationId, RowExclusiveLock);
3243 
3244  /* Make a TypeName so we can use standard type lookup machinery */
3245  typename = makeTypeNameFromNameList(names);
3246 
3247  /* Use LookupTypeName here so that shell types can be processed */
3248  tup = LookupTypeName(NULL, typename, NULL, false);
3249  if (tup == NULL)
3250  ereport(ERROR,
3251  (errcode(ERRCODE_UNDEFINED_OBJECT),
3252  errmsg("type \"%s\" does not exist",
3253  TypeNameToString(typename))));
3254  typeOid = typeTypeId(tup);
3255 
3256  /* Copy the syscache entry so we can scribble on it below */
3257  newtup = heap_copytuple(tup);
3258  ReleaseSysCache(tup);
3259  tup = newtup;
3260  typTup = (Form_pg_type) GETSTRUCT(tup);
3261 
3262  /* Don't allow ALTER DOMAIN on a type */
3263  if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN)
3264  ereport(ERROR,
3265  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3266  errmsg("%s is not a domain",
3267  format_type_be(typeOid))));
3268 
3269  /*
3270  * If it's a composite type, we need to check that it really is a
3271  * free-standing composite type, and not a table's rowtype. We want people
3272  * to use ALTER TABLE not ALTER TYPE for that case.
3273  */
3274  if (typTup->typtype == TYPTYPE_COMPOSITE &&
3275  get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
3276  ereport(ERROR,
3277  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3278  errmsg("%s is a table's row type",
3279  format_type_be(typeOid)),
3280  errhint("Use ALTER TABLE instead.")));
3281 
3282  /* don't allow direct alteration of array types, either */
3283  if (OidIsValid(typTup->typelem) &&
3284  get_array_type(typTup->typelem) == typeOid)
3285  ereport(ERROR,
3286  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
3287  errmsg("cannot alter array type %s",
3288  format_type_be(typeOid)),
3289  errhint("You can alter type %s, which will alter the array type as well.",
3290  format_type_be(typTup->typelem))));
3291 
3292  /*
3293  * If the new owner is the same as the existing owner, consider the
3294  * command to have succeeded. This is for dump restoration purposes.
3295  */
3296  if (typTup->typowner != newOwnerId)
3297  {
3298  /* Superusers can always do it */
3299  if (!superuser())
3300  {
3301  /* Otherwise, must be owner of the existing object */
3302  if (!pg_type_ownercheck(typTup->oid, GetUserId()))
3304 
3305  /* Must be able to become new owner */
3306  check_is_member_of_role(GetUserId(), newOwnerId);
3307 
3308  /* New owner must have CREATE privilege on namespace */
3309  aclresult = pg_namespace_aclcheck(typTup->typnamespace,
3310  newOwnerId,
3311  ACL_CREATE);
3312  if (aclresult != ACLCHECK_OK)
3313  aclcheck_error(aclresult, OBJECT_SCHEMA,
3314  get_namespace_name(typTup->typnamespace));
3315  }
3316 
3317  AlterTypeOwner_oid(typeOid, newOwnerId, true);
3318  }
3319 
3320  ObjectAddressSet(address, TypeRelationId, typeOid);
3321 
3322  /* Clean up */
3324 
3325  return address;
3326 }
Type LookupTypeName(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, bool missing_ok)
Definition: parse_type.c:38
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
int errhint(const char *fmt,...)
Definition: elog.c:1071
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Oid GetUserId(void)
Definition: miscinit.c:448
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:476
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2664
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1915
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
unsigned int Oid
Definition: postgres_ext.h:31
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4713
#define OidIsValid(objectId)
Definition: c.h:644
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4625
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3607
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
void AlterTypeOwner_oid(Oid typeOid, Oid newOwnerId, bool hasDependEntry)
Definition: typecmds.c:3340
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
#define RowExclusiveLock
Definition: lockdefs.h:38
void check_is_member_of_role(Oid member, Oid role)
Definition: acl.c:4938
AclResult
Definition: acl.h:177
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define ereport(elevel,...)
Definition: elog.h:144
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
int errmsg(const char *fmt,...)
Definition: elog.c:824
TypeName * makeTypeNameFromNameList(List *names)
Definition: makefuncs.c:456
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Oid typeTypeId(Type tp)
Definition: parse_type.c:588

◆ AlterTypeOwner_oid()

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

Definition at line 3340 of file typecmds.c.

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

Referenced by AlterTypeOwner(), and shdepReassignOwned().

3341 {
3342  Relation rel;
3343  HeapTuple tup;
3344  Form_pg_type typTup;
3345 
3346  rel = table_open(TypeRelationId, RowExclusiveLock);
3347 
3348  tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
3349  if (!HeapTupleIsValid(tup))
3350  elog(ERROR, "cache lookup failed for type %u", typeOid);
3351  typTup = (Form_pg_type) GETSTRUCT(tup);
3352 
3353  /*
3354  * If it's a composite type, invoke ATExecChangeOwner so that we fix up
3355  * the pg_class entry properly. That will call back to
3356  * AlterTypeOwnerInternal to take care of the pg_type entry(s).
3357  */
3358  if (typTup->typtype == TYPTYPE_COMPOSITE)
3359  ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock);
3360  else
3361  AlterTypeOwnerInternal(typeOid, newOwnerId);
3362 
3363  /* Update owner dependency reference */
3364  if (hasDependEntry)
3365  changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
3366 
3367  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3368 
3369  ReleaseSysCache(tup);
3371 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3380
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:309
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lockmode)
Definition: tablecmds.c:12378
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define elog(elevel,...)
Definition: elog.h:214
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

◆ AlterTypeOwnerInternal()

void AlterTypeOwnerInternal ( Oid  typeOid,
Oid  newOwnerId 
)

Definition at line 3380 of file typecmds.c.

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

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

3381 {
3382  Relation rel;
3383  HeapTuple tup;
3384  Form_pg_type typTup;
3385  Datum repl_val[Natts_pg_type];
3386  bool repl_null[Natts_pg_type];
3387  bool repl_repl[Natts_pg_type];
3388  Acl *newAcl;
3389  Datum aclDatum;
3390  bool isNull;
3391 
3392  rel = table_open(TypeRelationId, RowExclusiveLock);
3393 
3394  tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
3395  if (!HeapTupleIsValid(tup))
3396  elog(ERROR, "cache lookup failed for type %u", typeOid);
3397  typTup = (Form_pg_type) GETSTRUCT(tup);
3398 
3399  memset(repl_null, false, sizeof(repl_null));
3400  memset(repl_repl, false, sizeof(repl_repl));
3401 
3402  repl_repl[Anum_pg_type_typowner - 1] = true;
3403  repl_val[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(newOwnerId);
3404 
3405  aclDatum = heap_getattr(tup,
3406  Anum_pg_type_typacl,
3407  RelationGetDescr(rel),
3408  &isNull);
3409  /* Null ACLs do not require changes */
3410  if (!isNull)
3411  {
3412  newAcl = aclnewowner(DatumGetAclP(aclDatum),
3413  typTup->typowner, newOwnerId);
3414  repl_repl[Anum_pg_type_typacl - 1] = true;
3415  repl_val[Anum_pg_type_typacl - 1] = PointerGetDatum(newAcl);
3416  }
3417 
3418  tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
3419  repl_repl);
3420 
3421  CatalogTupleUpdate(rel, &tup->t_self, tup);
3422 
3423  /* If it has an array type, update that too */
3424  if (OidIsValid(typTup->typarray))
3425  AlterTypeOwnerInternal(typTup->typarray, newOwnerId);
3426 
3427  /* Clean up */
3429 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define RelationGetDescr(relation)
Definition: rel.h:482
#define DatumGetAclP(X)
Definition: acl.h:120
#define PointerGetDatum(X)
Definition: postgres.h:556
void AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId)
Definition: typecmds.c:3380
#define OidIsValid(objectId)
Definition: c.h:644
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#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:762
uintptr_t Datum
Definition: postgres.h:367
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
#define elog(elevel,...)
Definition: elog.h:214
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1044

◆ AlterTypeRecurse()

static void AlterTypeRecurse ( Oid  typeOid,
HeapTuple  tup,
Relation  catalog,
AlterTypeRecurseParams atparams 
)
static

Definition at line 3891 of file typecmds.c.

References AlterTypeRecurseParams::analyzeOid, BTEqualStrategyNumber, CatalogTupleUpdate(), CharGetDatum, check_stack_depth(), GenerateTypeDependencies(), GETSTRUCT, heap_modify_tuple(), InvalidOid, InvokeObjectPostAlterHook, sort-test::key, ObjectIdGetDatum, AlterTypeRecurseParams::receiveOid, RelationGetDescr, ScanKeyInit(), AlterTypeRecurseParams::sendOid, AlterTypeRecurseParams::storage, systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, AlterTypeRecurseParams::typmodinOid, AlterTypeRecurseParams::typmodoutOid, AlterTypeRecurseParams::updateAnalyze, AlterTypeRecurseParams::updateReceive, AlterTypeRecurseParams::updateSend, AlterTypeRecurseParams::updateStorage, AlterTypeRecurseParams::updateTypmodin, AlterTypeRecurseParams::updateTypmodout, and values.

Referenced by AlterType().

3893 {
3894  Datum values[Natts_pg_type];
3895  bool nulls[Natts_pg_type];
3896  bool replaces[Natts_pg_type];
3897  HeapTuple newtup;
3898  SysScanDesc scan;
3899  ScanKeyData key[1];
3900  HeapTuple domainTup;
3901 
3902  /* Since this function recurses, it could be driven to stack overflow */
3904 
3905  /* Update the current type's tuple */
3906  memset(values, 0, sizeof(values));
3907  memset(nulls, 0, sizeof(nulls));
3908  memset(replaces, 0, sizeof(replaces));
3909 
3910  if (atparams->updateStorage)
3911  {
3912  replaces[Anum_pg_type_typstorage - 1] = true;
3913  values[Anum_pg_type_typstorage - 1] = CharGetDatum(atparams->storage);
3914  }
3915  if (atparams->updateReceive)
3916  {
3917  replaces[Anum_pg_type_typreceive - 1] = true;
3918  values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(atparams->receiveOid);
3919  }
3920  if (atparams->updateSend)
3921  {
3922  replaces[Anum_pg_type_typsend - 1] = true;
3923  values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(atparams->sendOid);
3924  }
3925  if (atparams->updateTypmodin)
3926  {
3927  replaces[Anum_pg_type_typmodin - 1] = true;
3928  values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(atparams->typmodinOid);
3929  }
3930  if (atparams->updateTypmodout)
3931  {
3932  replaces[Anum_pg_type_typmodout - 1] = true;
3933  values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(atparams->typmodoutOid);
3934  }
3935  if (atparams->updateAnalyze)
3936  {
3937  replaces[Anum_pg_type_typanalyze - 1] = true;
3938  values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(atparams->analyzeOid);
3939  }
3940 
3941  newtup = heap_modify_tuple(tup, RelationGetDescr(catalog),
3942  values, nulls, replaces);
3943 
3944  CatalogTupleUpdate(catalog, &newtup->t_self, newtup);
3945 
3946  /* Rebuild dependencies for this type */
3947  GenerateTypeDependencies(newtup,
3948  catalog,
3949  NULL, /* don't have defaultExpr handy */
3950  NULL, /* don't have typacl handy */
3951  0, /* we rejected composite types above */
3952  false, /* and we rejected implicit arrays above */
3953  false, /* so it can't be a dependent type */
3954  true);
3955 
3956  InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
3957 
3958  /*
3959  * Now we need to recurse to domains. However, some properties are not
3960  * inherited by domains, so clear the update flags for those.
3961  */
3962  atparams->updateReceive = false; /* domains use F_DOMAIN_RECV */
3963  atparams->updateTypmodin = false; /* domains don't have typmods */
3964  atparams->updateTypmodout = false;
3965 
3966  /* Search pg_type for possible domains over this type */
3967  ScanKeyInit(&key[0],
3968  Anum_pg_type_typbasetype,
3969  BTEqualStrategyNumber, F_OIDEQ,
3970  ObjectIdGetDatum(typeOid));
3971 
3972  scan = systable_beginscan(catalog, InvalidOid, false,
3973  NULL, 1, key);
3974 
3975  while ((domainTup = systable_getnext(scan)) != NULL)
3976  {
3977  Form_pg_type domainForm = (Form_pg_type) GETSTRUCT(domainTup);
3978 
3979  /*
3980  * Shouldn't have a nonzero typbasetype in a non-domain, but let's
3981  * check
3982  */
3983  if (domainForm->typtype != TYPTYPE_DOMAIN)
3984  continue;
3985 
3986  AlterTypeRecurse(domainForm->oid, domainTup, catalog, atparams);
3987  }
3988 
3989  systable_endscan(scan);
3990 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define RelationGetDescr(relation)
Definition: rel.h:482
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
ItemPointerData t_self
Definition: htup.h:65
void check_stack_depth(void)
Definition: postgres.c:3312
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
uintptr_t Datum
Definition: postgres.h:367
#define InvalidOid
Definition: postgres_ext.h:36
void GenerateTypeDependencies(HeapTuple typeTuple, Relation typeCatalog, Node *defaultExpr, void *typacl, char relationKind, bool isImplicitArray, bool isDependentType, bool rebuild)
Definition: pg_type.c:542
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
#define CharGetDatum(X)
Definition: postgres.h:416
static Datum values[MAXATTR]
Definition: bootstrap.c:167
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
#define BTEqualStrategyNumber
Definition: stratnum.h:31
static void AlterTypeRecurse(Oid typeOid, HeapTuple tup, Relation catalog, AlterTypeRecurseParams *atparams)
Definition: typecmds.c:3891

◆ AssignTypeArrayOid()

Oid AssignTypeArrayOid ( void  )

Definition at line 2021 of file typecmds.c.

References AccessShareLock, binary_upgrade_next_array_pg_type_oid, ereport, errcode(), errmsg(), ERROR, GetNewOidWithIndex(), InvalidOid, IsBinaryUpgrade, OidIsValid, table_close(), table_open(), and TypeOidIndexId.

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

2022 {
2023  Oid type_array_oid;
2024 
2025  /* Use binary-upgrade override for pg_type.typarray? */
2026  if (IsBinaryUpgrade)
2027  {
2029  ereport(ERROR,
2030  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2031  errmsg("pg_type array OID value not set when in binary upgrade mode")));
2032 
2033  type_array_oid = binary_upgrade_next_array_pg_type_oid;
2035  }
2036  else
2037  {
2038  Relation pg_type = table_open(TypeRelationId, AccessShareLock);
2039 
2040  type_array_oid = GetNewOidWithIndex(pg_type, TypeOidIndexId,
2041  Anum_pg_type_oid);
2042  table_close(pg_type, AccessShareLock);
2043  }
2044 
2045  return type_array_oid;
2046 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
bool IsBinaryUpgrade
Definition: globals.c:110
#define ERROR
Definition: elog.h:43
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
Oid binary_upgrade_next_array_pg_type_oid
Definition: typecmds.c:107
int errmsg(const char *fmt,...)
Definition: elog.c:824
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define TypeOidIndexId
Definition: indexing.h:286

◆ checkDomainOwner()

void checkDomainOwner ( HeapTuple  tup)

Definition at line 2978 of file typecmds.c.

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

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

2979 {
2980  Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
2981 
2982  /* Check that this is actually a domain */
2983  if (typTup->typtype != TYPTYPE_DOMAIN)
2984  ereport(ERROR,
2985  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2986  errmsg("%s is not a domain",
2987  format_type_be(typTup->oid))));
2988 
2989  /* Permission check: must own type */
2990  if (!pg_type_ownercheck(typTup->oid, GetUserId()))
2992 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Oid GetUserId(void)
Definition: miscinit.c:448
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4713
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3607
#define ERROR
Definition: elog.h:43
#define ereport(elevel,...)
Definition: elog.h:144
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ checkEnumOwner()

static void checkEnumOwner ( HeapTuple  tup)
static

Definition at line 1262 of file typecmds.c.

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

Referenced by AlterEnum().

1263 {
1264  Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
1265 
1266  /* Check that this is actually an enum */
1267  if (typTup->typtype != TYPTYPE_ENUM)
1268  ereport(ERROR,
1269  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1270  errmsg("%s is not an enum",
1271  format_type_be(typTup->oid))));
1272 
1273  /* Permission check: must own type */
1274  if (!pg_type_ownercheck(typTup->oid, GetUserId()))
1276 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Oid GetUserId(void)
Definition: miscinit.c:448
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4713
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3607
#define ERROR
Definition: elog.h:43
#define ereport(elevel,...)
Definition: elog.h:144
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ DefineCompositeType()

ObjectAddress DefineCompositeType ( RangeVar typevar,
List coldeflist 
)

Definition at line 2063 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

2064 {
2065  CreateStmt *createStmt = makeNode(CreateStmt);
2066  Oid old_type_oid;
2067  Oid typeNamespace;
2068  ObjectAddress address;
2069 
2070  /*
2071  * now set the parameters for keys/inheritance etc. All of these are
2072  * uninteresting for composite types...
2073  */
2074  createStmt->relation = typevar;
2075  createStmt->tableElts = coldeflist;
2076  createStmt->inhRelations = NIL;
2077  createStmt->constraints = NIL;
2078  createStmt->options = NIL;
2079  createStmt->oncommit = ONCOMMIT_NOOP;
2080  createStmt->tablespacename = NULL;
2081  createStmt->if_not_exists = false;
2082 
2083  /*
2084  * Check for collision with an existing type name. If there is one and
2085  * it's an autogenerated array, we can rename it out of the way. This
2086  * check is here mainly to get a better error message about a "type"
2087  * instead of below about a "relation".
2088  */
2089  typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation,
2090  NoLock, NULL);
2091  RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace);
2092  old_type_oid =
2093  GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
2094  CStringGetDatum(createStmt->relation->relname),
2095  ObjectIdGetDatum(typeNamespace));
2096  if (OidIsValid(old_type_oid))
2097  {
2098  if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace))
2099  ereport(ERROR,
2101  errmsg("type \"%s\" already exists", createStmt->relation->relname)));
2102  }
2103 
2104  /*
2105  * Finally create the relation. This also creates the type.
2106  */
2107  DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address,
2108  NULL);
2109 
2110  return address;
2111 }
RangeVar * relation
Definition: parsenodes.h:2072
#define NIL
Definition: pg_list.h:65
OnCommitAction oncommit
Definition: parsenodes.h:2081
List * inhRelations
Definition: parsenodes.h:2074
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition: namespace.c:641
List * constraints
Definition: parsenodes.h:2079
bool if_not_exists
Definition: parsenodes.h:2084
char * relname
Definition: primnodes.h:68
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:846
#define NoLock
Definition: lockdefs.h:34
#define CStringGetDatum(X)
Definition: postgres.h:578
List * options
Definition: parsenodes.h:2080
ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ObjectAddress *typaddress, const char *queryString)
Definition: tablecmds.c:581
char * tablespacename
Definition: parsenodes.h:2082
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:534
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
List * tableElts
Definition: parsenodes.h:2073
#define makeNode(_type_)
Definition: nodes.h:577
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:194
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31

◆ DefineDomain()

ObjectAddress DefineDomain ( CreateDomainStmt stmt)

Definition at line 657 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

658 {
659  char *domainName;
660  char *domainArrayName;
661  Oid domainNamespace;
662  AclResult aclresult;
663  int16 internalLength;
664  Oid inputProcedure;
665  Oid outputProcedure;
666  Oid receiveProcedure;
667  Oid sendProcedure;
668  Oid analyzeProcedure;
669  bool byValue;
670  char category;
671  char delimiter;
672  char alignment;
673  char storage;
674  char typtype;
675  Datum datum;
676  bool isnull;
677  char *defaultValue = NULL;
678  char *defaultValueBin = NULL;
679  bool saw_default = false;
680  bool typNotNull = false;
681  bool nullDefined = false;
682  int32 typNDims = list_length(stmt->typeName->arrayBounds);
683  HeapTuple typeTup;
684  List *schema = stmt->constraints;
685  ListCell *listptr;
686  Oid basetypeoid;
687  Oid old_type_oid;
688  Oid domaincoll;
689  Oid domainArrayOid;
690  Form_pg_type baseType;
691  int32 basetypeMod;
692  Oid baseColl;
693  ObjectAddress address;
694 
695  /* Convert list of names to a name and namespace */
696  domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
697  &domainName);
698 
699  /* Check we have creation rights in target namespace */
700  aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(),
701  ACL_CREATE);
702  if (aclresult != ACLCHECK_OK)
703  aclcheck_error(aclresult, OBJECT_SCHEMA,
704  get_namespace_name(domainNamespace));
705 
706  /*
707  * Check for collision with an existing type name. If there is one and
708  * it's an autogenerated array, we can rename it out of the way.
709  */
710  old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
711  CStringGetDatum(domainName),
712  ObjectIdGetDatum(domainNamespace));
713  if (OidIsValid(old_type_oid))
714  {
715  if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace))
716  ereport(ERROR,
718  errmsg("type \"%s\" already exists", domainName)));
719  }
720 
721  /*
722  * Look up the base type.
723  */
724  typeTup = typenameType(NULL, stmt->typeName, &basetypeMod);
725  baseType = (Form_pg_type) GETSTRUCT(typeTup);
726  basetypeoid = baseType->oid;
727 
728  /*
729  * Base type must be a plain base type, a composite type, another domain,
730  * an enum or a range type. Domains over pseudotypes would create a
731  * security hole. (It would be shorter to code this to just check for
732  * pseudotypes; but it seems safer to call out the specific typtypes that
733  * are supported, rather than assume that all future typtypes would be
734  * automatically supported.)
735  */
736  typtype = baseType->typtype;
737  if (typtype != TYPTYPE_BASE &&
738  typtype != TYPTYPE_COMPOSITE &&
739  typtype != TYPTYPE_DOMAIN &&
740  typtype != TYPTYPE_ENUM &&
741  typtype != TYPTYPE_RANGE)
742  ereport(ERROR,
743  (errcode(ERRCODE_DATATYPE_MISMATCH),
744  errmsg("\"%s\" is not a valid base type for a domain",
745  TypeNameToString(stmt->typeName))));
746 
747  aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE);
748  if (aclresult != ACLCHECK_OK)
749  aclcheck_error_type(aclresult, basetypeoid);
750 
751  /*
752  * Collect the properties of the new domain. Some are inherited from the
753  * base type, some are not. If you change any of this inheritance
754  * behavior, be sure to update AlterTypeRecurse() to match!
755  */
756 
757  /*
758  * Identify the collation if any
759  */
760  baseColl = baseType->typcollation;
761  if (stmt->collClause)
762  domaincoll = get_collation_oid(stmt->collClause->collname, false);
763  else
764  domaincoll = baseColl;
765 
766  /* Complain if COLLATE is applied to an uncollatable type */
767  if (OidIsValid(domaincoll) && !OidIsValid(baseColl))
768  ereport(ERROR,
769  (errcode(ERRCODE_DATATYPE_MISMATCH),
770  errmsg("collations are not supported by type %s",
771  format_type_be(basetypeoid))));
772 
773  /* passed by value */
774  byValue = baseType->typbyval;
775 
776  /* Required Alignment */
777  alignment = baseType->typalign;
778 
779  /* TOAST Strategy */
780  storage = baseType->typstorage;
781 
782  /* Storage Length */
783  internalLength = baseType->typlen;
784 
785  /* Type Category */
786  category = baseType->typcategory;
787 
788  /* Array element Delimiter */
789  delimiter = baseType->typdelim;
790 
791  /* I/O Functions */
792  inputProcedure = F_DOMAIN_IN;
793  outputProcedure = baseType->typoutput;
794  receiveProcedure = F_DOMAIN_RECV;
795  sendProcedure = baseType->typsend;
796 
797  /* Domains never accept typmods, so no typmodin/typmodout needed */
798 
799  /* Analysis function */
800  analyzeProcedure = baseType->typanalyze;
801 
802  /* Inherited default value */
803  datum = SysCacheGetAttr(TYPEOID, typeTup,
804  Anum_pg_type_typdefault, &isnull);
805  if (!isnull)
806  defaultValue = TextDatumGetCString(datum);
807 
808  /* Inherited default binary value */
809  datum = SysCacheGetAttr(TYPEOID, typeTup,
810  Anum_pg_type_typdefaultbin, &isnull);
811  if (!isnull)
812  defaultValueBin = TextDatumGetCString(datum);
813 
814  /*
815  * Run through constraints manually to avoid the additional processing
816  * conducted by DefineRelation() and friends.
817  */
818  foreach(listptr, schema)
819  {
820  Constraint *constr = lfirst(listptr);
821 
822  if (!IsA(constr, Constraint))
823  elog(ERROR, "unrecognized node type: %d",
824  (int) nodeTag(constr));
825  switch (constr->contype)
826  {
827  case CONSTR_DEFAULT:
828 
829  /*
830  * The inherited default value may be overridden by the user
831  * with the DEFAULT <expr> clause ... but only once.
832  */
833  if (saw_default)
834  ereport(ERROR,
835  (errcode(ERRCODE_SYNTAX_ERROR),
836  errmsg("multiple default expressions")));
837  saw_default = true;
838 
839  if (constr->raw_expr)
840  {
841  ParseState *pstate;
842  Node *defaultExpr;
843 
844  /* Create a dummy ParseState for transformExpr */
845  pstate = make_parsestate(NULL);
846 
847  /*
848  * Cook the constr->raw_expr into an expression. Note:
849  * name is strictly for error message
850  */
851  defaultExpr = cookDefault(pstate, constr->raw_expr,
852  basetypeoid,
853  basetypeMod,
854  domainName,
855  0);
856 
857  /*
858  * If the expression is just a NULL constant, we treat it
859  * like not having a default.
860  *
861  * Note that if the basetype is another domain, we'll see
862  * a CoerceToDomain expr here and not discard the default.
863  * This is critical because the domain default needs to be
864  * retained to override any default that the base domain
865  * might have.
866  */
867  if (defaultExpr == NULL ||
868  (IsA(defaultExpr, Const) &&
869  ((Const *) defaultExpr)->constisnull))
870  {
871  defaultValue = NULL;
872  defaultValueBin = NULL;
873  }
874  else
875  {
876  /*
877  * Expression must be stored as a nodeToString result,
878  * but we also require a valid textual representation
879  * (mainly to make life easier for pg_dump).
880  */
881  defaultValue =
882  deparse_expression(defaultExpr,
883  NIL, false, false);
884  defaultValueBin = nodeToString(defaultExpr);
885  }
886  }
887  else
888  {
889  /* No default (can this still happen?) */
890  defaultValue = NULL;
891  defaultValueBin = NULL;
892  }
893  break;
894 
895  case CONSTR_NOTNULL:
896  if (nullDefined && !typNotNull)
897  ereport(ERROR,
898  (errcode(ERRCODE_SYNTAX_ERROR),
899  errmsg("conflicting NULL/NOT NULL constraints")));
900  typNotNull = true;
901  nullDefined = true;
902  break;
903 
904  case CONSTR_NULL:
905  if (nullDefined && typNotNull)
906  ereport(ERROR,
907  (errcode(ERRCODE_SYNTAX_ERROR),
908  errmsg("conflicting NULL/NOT NULL constraints")));
909  typNotNull = false;
910  nullDefined = true;
911  break;
912 
913  case CONSTR_CHECK:
914 
915  /*
916  * Check constraints are handled after domain creation, as
917  * they require the Oid of the domain; at this point we can
918  * only check that they're not marked NO INHERIT, because that
919  * would be bogus.
920  */
921  if (constr->is_no_inherit)
922  ereport(ERROR,
923  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
924  errmsg("check constraints for domains cannot be marked NO INHERIT")));
925  break;
926 
927  /*
928  * All else are error cases
929  */
930  case CONSTR_UNIQUE:
931  ereport(ERROR,
932  (errcode(ERRCODE_SYNTAX_ERROR),
933  errmsg("unique constraints not possible for domains")));
934  break;
935 
936  case CONSTR_PRIMARY:
937  ereport(ERROR,
938  (errcode(ERRCODE_SYNTAX_ERROR),
939  errmsg("primary key constraints not possible for domains")));
940  break;
941 
942  case CONSTR_EXCLUSION:
943  ereport(ERROR,
944  (errcode(ERRCODE_SYNTAX_ERROR),
945  errmsg("exclusion constraints not possible for domains")));
946  break;
947 
948  case CONSTR_FOREIGN:
949  ereport(ERROR,
950  (errcode(ERRCODE_SYNTAX_ERROR),
951  errmsg("foreign key constraints not possible for domains")));
952  break;
953 
958  ereport(ERROR,
959  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
960  errmsg("specifying constraint deferrability not supported for domains")));
961  break;
962 
963  default:
964  elog(ERROR, "unrecognized constraint subtype: %d",
965  (int) constr->contype);
966  break;
967  }
968  }
969 
970  /* Allocate OID for array type */
971  domainArrayOid = AssignTypeArrayOid();
972 
973  /*
974  * Have TypeCreate do all the real work.
975  */
976  address =
977  TypeCreate(InvalidOid, /* no predetermined type OID */
978  domainName, /* type name */
979  domainNamespace, /* namespace */
980  InvalidOid, /* relation oid (n/a here) */
981  0, /* relation kind (ditto) */
982  GetUserId(), /* owner's ID */
983  internalLength, /* internal size */
984  TYPTYPE_DOMAIN, /* type-type (domain type) */
985  category, /* type-category */
986  false, /* domain types are never preferred */
987  delimiter, /* array element delimiter */
988  inputProcedure, /* input procedure */
989  outputProcedure, /* output procedure */
990  receiveProcedure, /* receive procedure */
991  sendProcedure, /* send procedure */
992  InvalidOid, /* typmodin procedure - none */
993  InvalidOid, /* typmodout procedure - none */
994  analyzeProcedure, /* analyze procedure */
995  InvalidOid, /* no array element type */
996  false, /* this isn't an array */
997  domainArrayOid, /* array type we are about to create */
998  basetypeoid, /* base type ID */
999  defaultValue, /* default type value (text) */
1000  defaultValueBin, /* default type value (binary) */
1001  byValue, /* passed by value */
1002  alignment, /* required alignment */
1003  storage, /* TOAST strategy */
1004  basetypeMod, /* typeMod value */
1005  typNDims, /* Array dimensions for base type */
1006  typNotNull, /* Type NOT NULL */
1007  domaincoll); /* type's collation */
1008 
1009  /*
1010  * Create the array type that goes with it.
1011  */
1012  domainArrayName = makeArrayTypeName(domainName, domainNamespace);
1013 
1014  /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for arrays */
1015  alignment = (alignment == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
1016 
1017  TypeCreate(domainArrayOid, /* force assignment of this type OID */
1018  domainArrayName, /* type name */
1019  domainNamespace, /* namespace */
1020  InvalidOid, /* relation oid (n/a here) */
1021  0, /* relation kind (ditto) */
1022  GetUserId(), /* owner's ID */
1023  -1, /* internal size (always varlena) */
1024  TYPTYPE_BASE, /* type-type (base type) */
1025  TYPCATEGORY_ARRAY, /* type-category (array) */
1026  false, /* array types are never preferred */
1027  delimiter, /* array element delimiter */
1028  F_ARRAY_IN, /* input procedure */
1029  F_ARRAY_OUT, /* output procedure */
1030  F_ARRAY_RECV, /* receive procedure */
1031  F_ARRAY_SEND, /* send procedure */
1032  InvalidOid, /* typmodin procedure - none */
1033  InvalidOid, /* typmodout procedure - none */
1034  F_ARRAY_TYPANALYZE, /* analyze procedure */
1035  address.objectId, /* element type ID */
1036  true, /* yes this is an array type */
1037  InvalidOid, /* no further array type */
1038  InvalidOid, /* base type ID */
1039  NULL, /* never a default type value */
1040  NULL, /* binary default isn't sent either */
1041  false, /* never passed by value */
1042  alignment, /* see above */
1043  TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
1044  -1, /* typMod (Domains only) */
1045  0, /* Array dimensions of typbasetype */
1046  false, /* Type NOT NULL */
1047  domaincoll); /* type's collation */
1048 
1049  pfree(domainArrayName);
1050 
1051  /*
1052  * Process constraints which refer to the domain ID returned by TypeCreate
1053  */
1054  foreach(listptr, schema)
1055  {
1056  Constraint *constr = lfirst(listptr);
1057 
1058  /* it must be a Constraint, per check above */
1059 
1060  switch (constr->contype)
1061  {
1062  case CONSTR_CHECK:
1063  domainAddConstraint(address.objectId, domainNamespace,
1064  basetypeoid, basetypeMod,
1065  constr, domainName, NULL);
1066  break;
1067 
1068  /* Other constraint types were fully processed above */
1069 
1070  default:
1071  break;
1072  }
1073 
1074  /* CCI so we can detect duplicate constraint names */
1076  }
1077 
1078  /*
1079  * Now we can clean up.
1080  */
1081  ReleaseSysCache(typeTup);
1082 
1083  return address;
1084 }
signed short int16
Definition: c.h:354
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:785
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
Oid GetUserId(void)
Definition: miscinit.c:448
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2995
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:476
Node * raw_expr
Definition: parsenodes.h:2162
Definition: nodes.h:529
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Node * cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, const char *attname, char attgenerated)
Definition: heap.c:3003
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4625
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3607
signed int int32
Definition: c.h:355
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
static char * domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, const char *domainName, ObjectAddress *constrAddr)
Definition: typecmds.c:2998
void pfree(void *pointer)
Definition: mcxt.c:1056
CollateClause * collClause
Definition: parsenodes.h:2586
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:846
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ACL_USAGE
Definition: parsenodes.h:82
#define TextDatumGetCString(d)
Definition: builtins.h:88
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void CommandCounterIncrement(void)
Definition: xact.c:1006
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1377
#define InvalidOid
Definition: postgres_ext.h:36
bool is_no_inherit
Definition: parsenodes.h:2161
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:190
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:194
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:3223
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
static int list_length(const List *l)
Definition: pg_list.h:169
#define nodeTag(nodeptr)
Definition: nodes.h:534
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2021
TypeName * typeName
Definition: parsenodes.h:2585
List * collname
Definition: parsenodes.h:311
List * arrayBounds
Definition: parsenodes.h:216
int errmsg(const char *fmt,...)
Definition: elog.c:824
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:192
#define elog(elevel,...)
Definition: elog.h:214
char * nodeToString(const void *obj)
Definition: outfuncs.c:4360
ConstrType contype
Definition: parsenodes.h:2152
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4675
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3601
Definition: pg_list.h:50

◆ DefineEnum()

ObjectAddress DefineEnum ( CreateEnumStmt stmt)

Definition at line 1092 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

1093 {
1094  char *enumName;
1095  char *enumArrayName;
1096  Oid enumNamespace;
1097  AclResult aclresult;
1098  Oid old_type_oid;
1099  Oid enumArrayOid;
1100  ObjectAddress enumTypeAddr;
1101 
1102  /* Convert list of names to a name and namespace */
1103  enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1104  &enumName);
1105 
1106  /* Check we have creation rights in target namespace */
1107  aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
1108  if (aclresult != ACLCHECK_OK)
1109  aclcheck_error(aclresult, OBJECT_SCHEMA,
1110  get_namespace_name(enumNamespace));
1111 
1112  /*
1113  * Check for collision with an existing type name. If there is one and
1114  * it's an autogenerated array, we can rename it out of the way.
1115  */
1116  old_type_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
1117  CStringGetDatum(enumName),
1118  ObjectIdGetDatum(enumNamespace));
1119  if (OidIsValid(old_type_oid))
1120  {
1121  if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace))
1122  ereport(ERROR,
1124  errmsg("type \"%s\" already exists", enumName)));
1125  }
1126 
1127  /* Allocate OID for array type */
1128  enumArrayOid = AssignTypeArrayOid();
1129 
1130  /* Create the pg_type entry */
1131  enumTypeAddr =
1132  TypeCreate(InvalidOid, /* no predetermined type OID */
1133  enumName, /* type name */
1134  enumNamespace, /* namespace */
1135  InvalidOid, /* relation oid (n/a here) */
1136  0, /* relation kind (ditto) */
1137  GetUserId(), /* owner's ID */
1138  sizeof(Oid), /* internal size */
1139  TYPTYPE_ENUM, /* type-type (enum type) */
1140  TYPCATEGORY_ENUM, /* type-category (enum type) */
1141  false, /* enum types are never preferred */
1142  DEFAULT_TYPDELIM, /* array element delimiter */
1143  F_ENUM_IN, /* input procedure */
1144  F_ENUM_OUT, /* output procedure */
1145  F_ENUM_RECV, /* receive procedure */
1146  F_ENUM_SEND, /* send procedure */
1147  InvalidOid, /* typmodin procedure - none */
1148  InvalidOid, /* typmodout procedure - none */
1149  InvalidOid, /* analyze procedure - default */
1150  InvalidOid, /* element type ID */
1151  false, /* this is not an array type */
1152  enumArrayOid, /* array type we are about to create */
1153  InvalidOid, /* base type ID (only for domains) */
1154  NULL, /* never a default type value */
1155  NULL, /* binary default isn't sent either */
1156  true, /* always passed by value */
1157  TYPALIGN_INT, /* int alignment */
1158  TYPSTORAGE_PLAIN, /* TOAST strategy always plain */
1159  -1, /* typMod (Domains only) */
1160  0, /* Array dimensions of typbasetype */
1161  false, /* Type NOT NULL */
1162  InvalidOid); /* type's collation */
1163 
1164  /* Enter the enum's values into pg_enum */
1165  EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
1166 
1167  /*
1168  * Create the array type that goes with it.
1169  */
1170  enumArrayName = makeArrayTypeName(enumName, enumNamespace);
1171 
1172  TypeCreate(enumArrayOid, /* force assignment of this type OID */
1173  enumArrayName, /* type name */
1174  enumNamespace, /* namespace */
1175  InvalidOid, /* relation oid (n/a here) */
1176  0, /* relation kind (ditto) */
1177  GetUserId(), /* owner's ID */
1178  -1, /* internal size (always varlena) */
1179  TYPTYPE_BASE, /* type-type (base type) */
1180  TYPCATEGORY_ARRAY, /* type-category (array) */
1181  false, /* array types are never preferred */
1182  DEFAULT_TYPDELIM, /* array element delimiter */
1183  F_ARRAY_IN, /* input procedure */
1184  F_ARRAY_OUT, /* output procedure */
1185  F_ARRAY_RECV, /* receive procedure */
1186  F_ARRAY_SEND, /* send procedure */
1187  InvalidOid, /* typmodin procedure - none */
1188  InvalidOid, /* typmodout procedure - none */
1189  F_ARRAY_TYPANALYZE, /* analyze procedure */
1190  enumTypeAddr.objectId, /* element type ID */
1191  true, /* yes this is an array type */
1192  InvalidOid, /* no further array type */
1193  InvalidOid, /* base type ID */
1194  NULL, /* never a default type value */
1195  NULL, /* binary default isn't sent either */
1196  false, /* never passed by value */
1197  TYPALIGN_INT, /* enums have int align, so do their arrays */
1198  TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
1199  -1, /* typMod (Domains only) */
1200  0, /* Array dimensions of typbasetype */
1201  false, /* Type NOT NULL */
1202  InvalidOid); /* type's collation */
1203 
1204  pfree(enumArrayName);
1205 
1206  return enumTypeAddr;
1207 }
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:785
Oid GetUserId(void)
Definition: miscinit.c:448
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2995
int errcode(int sqlerrcode)
Definition: elog.c:610
void EnumValuesCreate(Oid enumTypeOid, List *vals)
Definition: pg_enum.c:60
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4625
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:846
#define CStringGetDatum(X)
Definition: postgres.h:578
AclResult
Definition: acl.h:177
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:194
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2021
int errmsg(const char *fmt,...)
Definition: elog.c:824
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:192
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31

◆ DefineRange()

ObjectAddress DefineRange ( CreateRangeStmt stmt)

Definition at line 1284 of file typecmds.c.

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, Assert, AssignTypeArrayOid(), CStringGetDatum, DEFAULT_TYPDELIM, defGetQualifiedName(), defGetTypeName(), DefElem::defname, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg(), ERROR, findRangeCanonicalFunction(), findRangeSubOpclass(), findRangeSubtypeDiffFunction(), format_type_be(), get_collation_oid(), get_namespace_name(), get_typcollation(), get_typisdefined(), get_typlenbyvalalign(), get_typtype(), GetSysCacheOid2, GetUserId(), InvalidOid, lfirst, makeArrayTypeName(), makeRangeConstructors(), moveArrayTypeName(), NIL, OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum, OidIsValid, CreateRangeStmt::params, pfree(), pg_namespace_aclcheck(), QualifiedNameGetCreationNamespace(), RangeCreate(), type_is_collatable(), TypeCreate(), CreateRangeStmt::typeName, TYPENAMENSP, and typenameTypeId().

Referenced by ProcessUtilitySlow().

1285 {
1286  char *typeName;
1287  Oid typeNamespace;
1288  Oid typoid;
1289  char *rangeArrayName;
1290  Oid rangeArrayOid;
1291  Oid rangeSubtype = InvalidOid;
1292  List *rangeSubOpclassName = NIL;
1293  List *rangeCollationName = NIL;
1294  List *rangeCanonicalName = NIL;
1295  List *rangeSubtypeDiffName = NIL;
1296  Oid rangeSubOpclass;
1297  Oid rangeCollation;
1298  regproc rangeCanonical;
1299  regproc rangeSubtypeDiff;
1300  int16 subtyplen;
1301  bool subtypbyval;
1302  char subtypalign;
1303  char alignment;
1304  AclResult aclresult;
1305  ListCell *lc;
1306  ObjectAddress address;
1307 
1308  /* Convert list of names to a name and namespace */
1309  typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
1310  &typeName);
1311 
1312  /* Check we have creation rights in target namespace */
1313  aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
1314  if (aclresult != ACLCHECK_OK)
1315  aclcheck_error(aclresult, OBJECT_SCHEMA,
1316  get_namespace_name(typeNamespace));
1317 
1318  /*
1319  * Look to see if type already exists.
1320  */
1321  typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
1322  CStringGetDatum(typeName),
1323  ObjectIdGetDatum(typeNamespace));
1324 
1325  /*
1326  * If it's not a shell, see if it's an autogenerated array type, and if so
1327  * rename it out of the way.
1328  */
1329  if (OidIsValid(typoid) && get_typisdefined(typoid))
1330  {
1331  if (moveArrayTypeName(typoid, typeName, typeNamespace))
1332  typoid = InvalidOid;
1333  else
1334  ereport(ERROR,
1336  errmsg("type \"%s\" already exists", typeName)));
1337  }
1338 
1339  /*
1340  * Unlike DefineType(), we don't insist on a shell type existing first, as
1341  * it's only needed if the user wants to specify a canonical function.
1342  */
1343 
1344  /* Extract the parameters from the parameter list */
1345  foreach(lc, stmt->params)
1346  {
1347  DefElem *defel = (DefElem *) lfirst(lc);
1348 
1349  if (strcmp(defel->defname, "subtype") == 0)
1350  {
1351  if (OidIsValid(rangeSubtype))
1352  ereport(ERROR,
1353  (errcode(ERRCODE_SYNTAX_ERROR),
1354  errmsg("conflicting or redundant options")));
1355  /* we can look up the subtype name immediately */
1356  rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel));
1357  }
1358  else if (strcmp(defel->defname, "subtype_opclass") == 0)
1359  {
1360  if (rangeSubOpclassName != NIL)
1361  ereport(ERROR,
1362  (errcode(ERRCODE_SYNTAX_ERROR),
1363  errmsg("conflicting or redundant options")));
1364  rangeSubOpclassName = defGetQualifiedName(defel);
1365  }
1366  else if (strcmp(defel->defname, "collation") == 0)
1367  {
1368  if (rangeCollationName != NIL)
1369  ereport(ERROR,
1370  (errcode(ERRCODE_SYNTAX_ERROR),
1371  errmsg("conflicting or redundant options")));
1372  rangeCollationName = defGetQualifiedName(defel);
1373  }
1374  else if (strcmp(defel->defname, "canonical") == 0)
1375  {
1376  if (rangeCanonicalName != NIL)
1377  ereport(ERROR,
1378  (errcode(ERRCODE_SYNTAX_ERROR),
1379  errmsg("conflicting or redundant options")));
1380  rangeCanonicalName = defGetQualifiedName(defel);
1381  }
1382  else if (strcmp(defel->defname, "subtype_diff") == 0)
1383  {
1384  if (rangeSubtypeDiffName != NIL)
1385  ereport(ERROR,
1386  (errcode(ERRCODE_SYNTAX_ERROR),
1387  errmsg("conflicting or redundant options")));
1388  rangeSubtypeDiffName = defGetQualifiedName(defel);
1389  }
1390  else
1391  ereport(ERROR,
1392  (errcode(ERRCODE_SYNTAX_ERROR),
1393  errmsg("type attribute \"%s\" not recognized",
1394  defel->defname)));
1395  }
1396 
1397  /* Must have a subtype */
1398  if (!OidIsValid(rangeSubtype))
1399  ereport(ERROR,
1400  (errcode(ERRCODE_SYNTAX_ERROR),
1401  errmsg("type attribute \"subtype\" is required")));
1402  /* disallow ranges of pseudotypes */
1403  if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO)
1404  ereport(ERROR,
1405  (errcode(ERRCODE_DATATYPE_MISMATCH),
1406  errmsg("range subtype cannot be %s",
1407  format_type_be(rangeSubtype))));
1408 
1409  /* Identify subopclass */
1410  rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
1411 
1412  /* Identify collation to use, if any */
1413  if (type_is_collatable(rangeSubtype))
1414  {
1415  if (rangeCollationName != NIL)
1416  rangeCollation = get_collation_oid(rangeCollationName, false);
1417  else
1418  rangeCollation = get_typcollation(rangeSubtype);
1419  }
1420  else
1421  {
1422  if (rangeCollationName != NIL)
1423  ereport(ERROR,
1424  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1425  errmsg("range collation specified but subtype does not support collation")));
1426  rangeCollation = InvalidOid;
1427  }
1428 
1429  /* Identify support functions, if provided */
1430  if (rangeCanonicalName != NIL)
1431  {
1432  if (!OidIsValid(typoid))
1433  ereport(ERROR,
1434  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1435  errmsg("cannot specify a canonical function without a pre-created shell type"),
1436  errhint("Create the type as a shell type, then create its canonicalization function, then do a full CREATE TYPE.")));
1437  rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
1438  typoid);
1439  }
1440  else
1441  rangeCanonical = InvalidOid;
1442 
1443  if (rangeSubtypeDiffName != NIL)
1444  rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1445  rangeSubtype);
1446  else
1447  rangeSubtypeDiff = InvalidOid;
1448 
1449  get_typlenbyvalalign(rangeSubtype,
1450  &subtyplen, &subtypbyval, &subtypalign);
1451 
1452  /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for ranges */
1453  alignment = (subtypalign == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
1454 
1455  /* Allocate OID for array type */
1456  rangeArrayOid = AssignTypeArrayOid();
1457 
1458  /* Create the pg_type entry */
1459  address =
1460  TypeCreate(InvalidOid, /* no predetermined type OID */
1461  typeName, /* type name */
1462  typeNamespace, /* namespace */
1463  InvalidOid, /* relation oid (n/a here) */
1464  0, /* relation kind (ditto) */
1465  GetUserId(), /* owner's ID */
1466  -1, /* internal size (always varlena) */
1467  TYPTYPE_RANGE, /* type-type (range type) */
1468  TYPCATEGORY_RANGE, /* type-category (range type) */
1469  false, /* range types are never preferred */
1470  DEFAULT_TYPDELIM, /* array element delimiter */
1471  F_RANGE_IN, /* input procedure */
1472  F_RANGE_OUT, /* output procedure */
1473  F_RANGE_RECV, /* receive procedure */
1474  F_RANGE_SEND, /* send procedure */
1475  InvalidOid, /* typmodin procedure - none */
1476  InvalidOid, /* typmodout procedure - none */
1477  F_RANGE_TYPANALYZE, /* analyze procedure */
1478  InvalidOid, /* element type ID - none */
1479  false, /* this is not an array type */
1480  rangeArrayOid, /* array type we are about to create */
1481  InvalidOid, /* base type ID (only for domains) */
1482  NULL, /* never a default type value */
1483  NULL, /* no binary form available either */
1484  false, /* never passed by value */
1485  alignment, /* alignment */
1486  TYPSTORAGE_EXTENDED, /* TOAST strategy (always extended) */
1487  -1, /* typMod (Domains only) */
1488  0, /* Array dimensions of typbasetype */
1489  false, /* Type NOT NULL */
1490  InvalidOid); /* type's collation (ranges never have one) */
1491  Assert(typoid == InvalidOid || typoid == address.objectId);
1492  typoid = address.objectId;
1493 
1494  /* Create the entry in pg_range */
1495  RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
1496  rangeCanonical, rangeSubtypeDiff);
1497 
1498  /*
1499  * Create the array type that goes with it.
1500  */
1501  rangeArrayName = makeArrayTypeName(typeName, typeNamespace);
1502 
1503  TypeCreate(rangeArrayOid, /* force assignment of this type OID */
1504  rangeArrayName, /* type name */
1505  typeNamespace, /* namespace */
1506  InvalidOid, /* relation oid (n/a here) */
1507  0, /* relation kind (ditto) */
1508  GetUserId(), /* owner's ID */
1509  -1, /* internal size (always varlena) */
1510  TYPTYPE_BASE, /* type-type (base type) */
1511  TYPCATEGORY_ARRAY, /* type-category (array) */
1512  false, /* array types are never preferred */
1513  DEFAULT_TYPDELIM, /* array element delimiter */
1514  F_ARRAY_IN, /* input procedure */
1515  F_ARRAY_OUT, /* output procedure */
1516  F_ARRAY_RECV, /* receive procedure */
1517  F_ARRAY_SEND, /* send procedure */
1518  InvalidOid, /* typmodin procedure - none */
1519  InvalidOid, /* typmodout procedure - none */
1520  F_ARRAY_TYPANALYZE, /* analyze procedure */
1521  typoid, /* element type ID */
1522  true, /* yes this is an array type */
1523  InvalidOid, /* no further array type */
1524  InvalidOid, /* base type ID */
1525  NULL, /* never a default type value */
1526  NULL, /* binary default isn't sent either */
1527  false, /* never passed by value */
1528  alignment, /* alignment - same as range's */
1529  TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
1530  -1, /* typMod (Domains only) */
1531  0, /* Array dimensions of typbasetype */
1532  false, /* Type NOT NULL */
1533  InvalidOid); /* typcollation */
1534 
1535  pfree(rangeArrayName);
1536 
1537  /* And create the constructor functions for this range type */
1538  makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype);
1539 
1540  return address;
1541 }
signed short int16
Definition: c.h:354
#define NIL
Definition: pg_list.h:65
static void makeRangeConstructors(const char *name, Oid namespace, Oid rangeOid, Oid subtype)
Definition: typecmds.c:1553
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:785
int errhint(const char *fmt,...)
Definition: elog.c:1071
Oid GetUserId(void)
Definition: miscinit.c:448
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2995
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2159
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:2061
int errcode(int sqlerrcode)
Definition: elog.c:610
char get_typtype(Oid typid)
Definition: lsyscache.c:2517
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4625
static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype)
Definition: typecmds.c:1973
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:255
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
void RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, Oid rangeSubOpclass, RegProcedure rangeCanonical, RegProcedure rangeSubDiff)
Definition: pg_range.c:36
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:846
#define CStringGetDatum(X)
Definition: postgres.h:578
AclResult
Definition: acl.h:177
#define InvalidOid
Definition: postgres_ext.h:36
static Oid findRangeSubOpclass(List *opcname, Oid subtype)
Definition: typecmds.c:1893
#define ereport(elevel,...)
Definition: elog.h:144
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:2933
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:194
List * defGetQualifiedName(DefElem *def)
Definition: define.c:223
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2021
Oid regproc
Definition: c.h:510
int errmsg(const char *fmt,...)
Definition: elog.c:824
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:192
char * defname
Definition: parsenodes.h:732
bool type_is_collatable(Oid typid)
Definition: lsyscache.c:2958
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
Oid get_collation_oid(List *name, bool missing_ok)
Definition: namespace.c:3601
Definition: pg_list.h:50
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1932
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ DefineType()

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

Definition at line 139 of file typecmds.c.

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

Referenced by ProcessUtilitySlow().

140 {
141  char *typeName;
142  Oid typeNamespace;
143  int16 internalLength = -1; /* default: variable-length */
144  List *inputName = NIL;
145  List *outputName = NIL;
146  List *receiveName = NIL;
147  List *sendName = NIL;
148  List *typmodinName = NIL;
149  List *typmodoutName = NIL;
150  List *analyzeName = NIL;
151  char category = TYPCATEGORY_USER;
152  bool preferred = false;
153  char delimiter = DEFAULT_TYPDELIM;
154  Oid elemType = InvalidOid;
155  char *defaultValue = NULL;
156  bool byValue = false;
157  char alignment = TYPALIGN_INT; /* default alignment */
158  char storage = TYPSTORAGE_PLAIN; /* default TOAST storage method */
159  Oid collation = InvalidOid;
160  DefElem *likeTypeEl = NULL;
161  DefElem *internalLengthEl = NULL;
162  DefElem *inputNameEl = NULL;
163  DefElem *outputNameEl = NULL;
164  DefElem *receiveNameEl = NULL;
165  DefElem *sendNameEl = NULL;
166  DefElem *typmodinNameEl = NULL;
167  DefElem *typmodoutNameEl = NULL;
168  DefElem *analyzeNameEl = NULL;
169  DefElem *categoryEl = NULL;
170  DefElem *preferredEl = NULL;
171  DefElem *delimiterEl = NULL;
172  DefElem *elemTypeEl = NULL;
173  DefElem *defaultValueEl = NULL;
174  DefElem *byValueEl = NULL;
175  DefElem *alignmentEl = NULL;
176  DefElem *storageEl = NULL;
177  DefElem *collatableEl = NULL;
178  Oid inputOid;
179  Oid outputOid;
180  Oid receiveOid = InvalidOid;
181  Oid sendOid = InvalidOid;
182  Oid typmodinOid = InvalidOid;
183  Oid typmodoutOid = InvalidOid;
184  Oid analyzeOid = InvalidOid;
185  char *array_type;
186  Oid array_oid;
187  Oid typoid;
188  ListCell *pl;
189  ObjectAddress address;
190 
191  /*
192  * As of Postgres 8.4, we require superuser privilege to create a base
193  * type. This is simple paranoia: there are too many ways to mess up the
194  * system with an incorrect type definition (for instance, representation
195  * parameters that don't match what the C code expects). In practice it
196  * takes superuser privilege to create the I/O functions, and so the
197  * former requirement that you own the I/O functions pretty much forced
198  * superuserness anyway. We're just making doubly sure here.
199  *
200  * XXX re-enable NOT_USED code sections below if you remove this test.
201  */
202  if (!superuser())
203  ereport(ERROR,
204  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
205  errmsg("must be superuser to create a base type")));
206 
207  /* Convert list of names to a name and namespace */
208  typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
209 
210 #ifdef NOT_USED
211  /* XXX this is unnecessary given the superuser check above */
212  /* Check we have creation rights in target namespace */
213  aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE);
214  if (aclresult != ACLCHECK_OK)
215  aclcheck_error(aclresult, OBJECT_SCHEMA,
216  get_namespace_name(typeNamespace));
217 #endif
218 
219  /*
220  * Look to see if type already exists.
221  */
222  typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
223  CStringGetDatum(typeName),
224  ObjectIdGetDatum(typeNamespace));
225 
226  /*
227  * If it's not a shell, see if it's an autogenerated array type, and if so
228  * rename it out of the way.
229  */
230  if (OidIsValid(typoid) && get_typisdefined(typoid))
231  {
232  if (moveArrayTypeName(typoid, typeName, typeNamespace))
233  typoid = InvalidOid;
234  else
235  ereport(ERROR,
237  errmsg("type \"%s\" already exists", typeName)));
238  }
239 
240  /*
241  * If this command is a parameterless CREATE TYPE, then we're just here to
242  * make a shell type, so do that (or fail if there already is a shell).
243  */
244  if (parameters == NIL)
245  {
246  if (OidIsValid(typoid))
247  ereport(ERROR,
249  errmsg("type \"%s\" already exists", typeName)));
250 
251  address = TypeShellMake(typeName, typeNamespace, GetUserId());
252  return address;
253  }
254 
255  /*
256  * Otherwise, we must already have a shell type, since there is no other
257  * way that the I/O functions could have been created.
258  */
259  if (!OidIsValid(typoid))
260  ereport(ERROR,
262  errmsg("type \"%s\" does not exist", typeName),
263  errhint("Create the type as a shell type, then create its I/O functions, then do a full CREATE TYPE.")));
264 
265  /* Extract the parameters from the parameter list */
266  foreach(pl, parameters)
267  {
268  DefElem *defel = (DefElem *) lfirst(pl);
269  DefElem **defelp;
270 
271  if (strcmp(defel->defname, "like") == 0)
272  defelp = &likeTypeEl;
273  else if (strcmp(defel->defname, "internallength") == 0)
274  defelp = &internalLengthEl;
275  else if (strcmp(defel->defname, "input") == 0)
276  defelp = &inputNameEl;
277  else if (strcmp(defel->defname, "output") == 0)
278  defelp = &outputNameEl;
279  else if (strcmp(defel->defname, "receive") == 0)
280  defelp = &receiveNameEl;
281  else if (strcmp(defel->defname, "send") == 0)
282  defelp = &sendNameEl;
283  else if (strcmp(defel->defname, "typmod_in") == 0)
284  defelp = &typmodinNameEl;
285  else if (strcmp(defel->defname, "typmod_out") == 0)
286  defelp = &typmodoutNameEl;
287  else if (strcmp(defel->defname, "analyze") == 0 ||
288  strcmp(defel->defname, "analyse") == 0)
289  defelp = &analyzeNameEl;
290  else if (strcmp(defel->defname, "category") == 0)
291  defelp = &categoryEl;
292  else if (strcmp(defel->defname, "preferred") == 0)
293  defelp = &preferredEl;
294  else if (strcmp(defel->defname, "delimiter") == 0)
295  defelp = &delimiterEl;
296  else if (strcmp(defel->defname, "element") == 0)
297  defelp = &elemTypeEl;
298  else if (strcmp(defel->defname, "default") == 0)
299  defelp = &defaultValueEl;
300  else if (strcmp(defel->defname, "passedbyvalue") == 0)
301  defelp = &byValueEl;
302  else if (strcmp(defel->defname, "alignment") == 0)
303  defelp = &alignmentEl;
304  else if (strcmp(defel->defname, "storage") == 0)
305  defelp = &storageEl;
306  else if (strcmp(defel->defname, "collatable") == 0)
307  defelp = &collatableEl;
308  else
309  {
310  /* WARNING, not ERROR, for historical backwards-compatibility */
312  (errcode(ERRCODE_SYNTAX_ERROR),
313  errmsg("type attribute \"%s\" not recognized",
314  defel->defname),
315  parser_errposition(pstate, defel->location)));
316  continue;
317  }
318  if (*defelp != NULL)
319  ereport(ERROR,
320  (errcode(ERRCODE_SYNTAX_ERROR),
321  errmsg("conflicting or redundant options"),
322  parser_errposition(pstate, defel->location)));
323  *defelp = defel;
324  }
325 
326  /*
327  * Now interpret the options; we do this separately so that LIKE can be
328  * overridden by other options regardless of the ordering in the parameter
329  * list.
330  */
331  if (likeTypeEl)
332  {
333  Type likeType;
334  Form_pg_type likeForm;
335 
336  likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL);
337  likeForm = (Form_pg_type) GETSTRUCT(likeType);
338  internalLength = likeForm->typlen;
339  byValue = likeForm->typbyval;
340  alignment = likeForm->typalign;
341  storage = likeForm->typstorage;
342  ReleaseSysCache(likeType);
343  }
344  if (internalLengthEl)
345  internalLength = defGetTypeLength(internalLengthEl);
346  if (inputNameEl)
347  inputName = defGetQualifiedName(inputNameEl);
348  if (outputNameEl)
349  outputName = defGetQualifiedName(outputNameEl);
350  if (receiveNameEl)
351  receiveName = defGetQualifiedName(receiveNameEl);
352  if (sendNameEl)
353  sendName = defGetQualifiedName(sendNameEl);
354  if (typmodinNameEl)
355  typmodinName = defGetQualifiedName(typmodinNameEl);
356  if (typmodoutNameEl)
357  typmodoutName = defGetQualifiedName(typmodoutNameEl);
358  if (analyzeNameEl)
359  analyzeName = defGetQualifiedName(analyzeNameEl);
360  if (categoryEl)
361  {
362  char *p = defGetString(categoryEl);
363 
364  category = p[0];
365  /* restrict to non-control ASCII */
366  if (category < 32 || category > 126)
367  ereport(ERROR,
368  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
369  errmsg("invalid type category \"%s\": must be simple ASCII",
370  p)));
371  }
372  if (preferredEl)
373  preferred = defGetBoolean(preferredEl);
374  if (delimiterEl)
375  {
376  char *p = defGetString(delimiterEl);
377 
378  delimiter = p[0];
379  /* XXX shouldn't we restrict the delimiter? */
380  }
381  if (elemTypeEl)
382  {
383  elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl));
384  /* disallow arrays of pseudotypes */
385  if (get_typtype(elemType) == TYPTYPE_PSEUDO)
386  ereport(ERROR,
387  (errcode(ERRCODE_DATATYPE_MISMATCH),
388  errmsg("array element type cannot be %s",
389  format_type_be(elemType))));
390  }
391  if (defaultValueEl)
392  defaultValue = defGetString(defaultValueEl);
393  if (byValueEl)
394  byValue = defGetBoolean(byValueEl);
395  if (alignmentEl)
396  {
397  char *a = defGetString(alignmentEl);
398 
399  /*
400  * Note: if argument was an unquoted identifier, parser will have
401  * applied translations to it, so be prepared to recognize translated
402  * type names as well as the nominal form.
403  */
404  if (pg_strcasecmp(a, "double") == 0 ||
405  pg_strcasecmp(a, "float8") == 0 ||
406  pg_strcasecmp(a, "pg_catalog.float8") == 0)
407  alignment = TYPALIGN_DOUBLE;
408  else if (pg_strcasecmp(a, "int4") == 0 ||
409  pg_strcasecmp(a, "pg_catalog.int4") == 0)
410  alignment = TYPALIGN_INT;
411  else if (pg_strcasecmp(a, "int2") == 0 ||
412  pg_strcasecmp(a, "pg_catalog.int2") == 0)
413  alignment = TYPALIGN_SHORT;
414  else if (pg_strcasecmp(a, "char") == 0 ||
415  pg_strcasecmp(a, "pg_catalog.bpchar") == 0)
416  alignment = TYPALIGN_CHAR;
417  else
418  ereport(ERROR,
419  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
420  errmsg("alignment \"%s\" not recognized", a)));
421  }
422  if (storageEl)
423  {
424  char *a = defGetString(storageEl);
425 
426  if (pg_strcasecmp(a, "plain") == 0)
427  storage = TYPSTORAGE_PLAIN;
428  else if (pg_strcasecmp(a, "external") == 0)
429  storage = TYPSTORAGE_EXTERNAL;
430  else if (pg_strcasecmp(a, "extended") == 0)
431  storage = TYPSTORAGE_EXTENDED;
432  else if (pg_strcasecmp(a, "main") == 0)
433  storage = TYPSTORAGE_MAIN;
434  else
435  ereport(ERROR,
436  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
437  errmsg("storage \"%s\" not recognized", a)));
438  }
439  if (collatableEl)
440  collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid;
441 
442  /*
443  * make sure we have our required definitions
444  */
445  if (inputName == NIL)
446  ereport(ERROR,
447  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
448  errmsg("type input function must be specified")));
449  if (outputName == NIL)
450  ereport(ERROR,
451  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
452  errmsg("type output function must be specified")));
453 
454  if (typmodinName == NIL && typmodoutName != NIL)
455  ereport(ERROR,
456  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
457  errmsg("type modifier output function is useless without a type modifier input function")));
458 
459  /*
460  * Convert I/O proc names to OIDs
461  */
462  inputOid = findTypeInputFunction(inputName, typoid);
463  outputOid = findTypeOutputFunction(outputName, typoid);
464  if (receiveName)
465  receiveOid = findTypeReceiveFunction(receiveName, typoid);
466  if (sendName)
467  sendOid = findTypeSendFunction(sendName, typoid);
468 
469  /*
470  * Convert typmodin/out function proc names to OIDs.
471  */
472  if (typmodinName)
473  typmodinOid = findTypeTypmodinFunction(typmodinName);
474  if (typmodoutName)
475  typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
476 
477  /*
478  * Convert analysis function proc name to an OID. If no analysis function
479  * is specified, we'll use zero to select the built-in default algorithm.
480  */
481  if (analyzeName)
482  analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid);
483 
484  /*
485  * Check permissions on functions. We choose to require the creator/owner
486  * of a type to also own the underlying functions. Since creating a type
487  * is tantamount to granting public execute access on the functions, the
488  * minimum sane check would be for execute-with-grant-option. But we
489  * don't have a way to make the type go away if the grant option is
490  * revoked, so ownership seems better.
491  *
492  * XXX For now, this is all unnecessary given the superuser check above.
493  * If we ever relax that, these calls likely should be moved into
494  * findTypeInputFunction et al, where they could be shared by AlterType.
495  */
496 #ifdef NOT_USED
497  if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId()))
499  NameListToString(inputName));
500  if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId()))
502  NameListToString(outputName));
503  if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId()))
505  NameListToString(receiveName));
506  if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
508  NameListToString(sendName));
509  if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
511  NameListToString(typmodinName));
512  if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
514  NameListToString(typmodoutName));
515  if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
517  NameListToString(analyzeName));
518 #endif
519 
520  /*
521  * OK, we're done checking, time to make the type. We must assign the
522  * array type OID ahead of calling TypeCreate, since the base type and
523  * array type each refer to the other.
524  */
525  array_oid = AssignTypeArrayOid();
526 
527  /*
528  * now have TypeCreate do all the real work.
529  *
530  * Note: the pg_type.oid is stored in user tables as array elements (base
531  * types) in ArrayType and in composite types in DatumTupleFields. This
532  * oid must be preserved by binary upgrades.
533  */
534  address =
535  TypeCreate(InvalidOid, /* no predetermined type OID */
536  typeName, /* type name */
537  typeNamespace, /* namespace */
538  InvalidOid, /* relation oid (n/a here) */
539  0, /* relation kind (ditto) */
540  GetUserId(), /* owner's ID */
541  internalLength, /* internal size */
542  TYPTYPE_BASE, /* type-type (base type) */
543  category, /* type-category */
544  preferred, /* is it a preferred type? */
545  delimiter, /* array element delimiter */
546  inputOid, /* input procedure */
547  outputOid, /* output procedure */
548  receiveOid, /* receive procedure */
549  sendOid, /* send procedure */
550  typmodinOid, /* typmodin procedure */
551  typmodoutOid, /* typmodout procedure */
552  analyzeOid, /* analyze procedure */
553  elemType, /* element type ID */
554  false, /* this is not an array type */
555  array_oid, /* array type we are about to create */
556  InvalidOid, /* base type ID (only for domains) */
557  defaultValue, /* default type value */
558  NULL, /* no binary form available */
559  byValue, /* passed by value */
560  alignment, /* required alignment */
561  storage, /* TOAST strategy */
562  -1, /* typMod (Domains only) */
563  0, /* Array Dimensions of typbasetype */
564  false, /* Type NOT NULL */
565  collation); /* type's collation */
566  Assert(typoid == address.objectId);
567 
568  /*
569  * Create the array type that goes with it.
570  */
571  array_type = makeArrayTypeName(typeName, typeNamespace);
572 
573  /* alignment must be TYPALIGN_INT or TYPALIGN_DOUBLE for arrays */
574  alignment = (alignment == TYPALIGN_DOUBLE) ? TYPALIGN_DOUBLE : TYPALIGN_INT;
575 
576  TypeCreate(array_oid, /* force assignment of this type OID */
577  array_type, /* type name */
578  typeNamespace, /* namespace */
579  InvalidOid, /* relation oid (n/a here) */
580  0, /* relation kind (ditto) */
581  GetUserId(), /* owner's ID */
582  -1, /* internal size (always varlena) */
583  TYPTYPE_BASE, /* type-type (base type) */
584  TYPCATEGORY_ARRAY, /* type-category (array) */
585  false, /* array types are never preferred */
586  delimiter, /* array element delimiter */
587  F_ARRAY_IN, /* input procedure */
588  F_ARRAY_OUT, /* output procedure */
589  F_ARRAY_RECV, /* receive procedure */
590  F_ARRAY_SEND, /* send procedure */
591  typmodinOid, /* typmodin procedure */
592  typmodoutOid, /* typmodout procedure */
593  F_ARRAY_TYPANALYZE, /* analyze procedure */
594  typoid, /* element type ID */
595  true, /* yes this is an array type */
596  InvalidOid, /* no further array type */
597  InvalidOid, /* base type ID */
598  NULL, /* never a default type value */
599  NULL, /* binary default isn't sent either */
600  false, /* never passed by value */
601  alignment, /* see above */
602  TYPSTORAGE_EXTENDED, /* ARRAY is always toastable */
603  -1, /* typMod (Domains only) */
604  0, /* Array dimensions of typbasetype */
605  false, /* Type NOT NULL */
606  collation); /* type's collation */
607 
608  pfree(array_type);
609 
610  return address;
611 }
signed short int16
Definition: c.h:354
#define NIL
Definition: pg_list.h:65
char * makeArrayTypeName(const char *typeName, Oid typeNamespace)
Definition: pg_type.c:785
int errhint(const char *fmt,...)
Definition: elog.c:1071
static Oid findTypeOutputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1677
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:264
static Oid findTypeReceiveFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1712
Oid GetUserId(void)
Definition: miscinit.c:448
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2995
static Oid findTypeTypmodinFunction(List *procname)
Definition: typecmds.c:1790
bool get_typisdefined(Oid typid)
Definition: lsyscache.c:2061
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
char get_typtype(Oid typid)
Definition: lsyscache.c:2517
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
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:644
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4625
int defGetTypeLength(DefElem *def)
Definition: define.c:283
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
bool defGetBoolean(DefElem *def)
Definition: define.c:111
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:255
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
char * defGetString(DefElem *def)
Definition: define.c:49
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1858
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace)
Definition: pg_type.c:846
int location
Definition: parsenodes.h:735
#define CStringGetDatum(X)
Definition: postgres.h:578
static Oid findTypeTypmodoutFunction(List *procname)
Definition: typecmds.c:1824
#define WARNING
Definition: elog.h:40
char * NameListToString(List *names)
Definition: namespace.c:3102
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define DEFAULT_TYPDELIM
Definition: typecmds.h:22
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:194
List * defGetQualifiedName(DefElem *def)
Definition: define.c:223
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
Oid AssignTypeArrayOid(void)
Definition: typecmds.c:2021
static Oid findTypeInputFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1625
int errmsg(const char *fmt,...)
Definition: elog.c:824
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:192
char * defname
Definition: parsenodes.h:732
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
Definition: pg_list.h:50
bool pg_proc_ownercheck(Oid proc_oid, Oid roleid)
Definition: aclchk.c:4765
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
static Oid findTypeSendFunction(List *procname, Oid typeOid)
Definition: typecmds.c:1755

◆ domainAddConstraint()

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

Definition at line 2998 of file typecmds.c.

References assign_expr_collations(), ChooseConstraintName(), coerce_to_boolean(), CoerceToDomainValue::collation, Constraint::conname, CONSTRAINT_DOMAIN, ConstraintNameIsUsed(), contain_var_clause(), CreateConstraintEntry(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, EXPR_KIND_DOMAIN_CHECK, get_typcollation(), InvalidOid, list_length(), CoerceToDomainValue::location, make_parsestate(), makeNode, NIL, nodeToString(), ObjectAddressSet, ParseState::p_pre_columnref_hook, ParseState::p_ref_hook_state, ParseState::p_rtable, Constraint::raw_expr, replace_domain_constraint_value(), Constraint::skip_validation, transformExpr(), CoerceToDomainValue::typeId, and CoerceToDomainValue::typeMod.

Referenced by AlterDomainAddConstraint(), and DefineDomain().

3001 {
3002  Node *expr;
3003  char *ccbin;
3004  ParseState *pstate;
3005  CoerceToDomainValue *domVal;
3006  Oid ccoid;
3007 
3008  /*
3009  * Assign or validate constraint name
3010  */
3011  if (constr->conname)
3012  {
3014  domainOid,
3015  constr->conname))
3016  ereport(ERROR,
3018  errmsg("constraint \"%s\" for domain \"%s\" already exists",
3019  constr->conname, domainName)));
3020  }
3021  else
3022  constr->conname = ChooseConstraintName(domainName,
3023  NULL,
3024  "check",
3025  domainNamespace,
3026  NIL);
3027 
3028  /*
3029  * Convert the A_EXPR in raw_expr into an EXPR
3030  */
3031  pstate = make_parsestate(NULL);
3032 
3033  /*
3034  * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
3035  * the expression. Note that it will appear to have the type of the base
3036  * type, not the domain. This seems correct since within the check
3037  * expression, we should not assume the input value can be considered a
3038  * member of the domain.
3039  */
3040  domVal = makeNode(CoerceToDomainValue);
3041  domVal->typeId = baseTypeOid;
3042  domVal->typeMod = typMod;
3043  domVal->collation = get_typcollation(baseTypeOid);
3044  domVal->location = -1; /* will be set when/if used */
3045 
3047  pstate->p_ref_hook_state = (void *) domVal;
3048 
3049  expr = transformExpr(pstate, constr->raw_expr, EXPR_KIND_DOMAIN_CHECK);
3050 
3051  /*
3052  * Make sure it yields a boolean result.
3053  */
3054  expr = coerce_to_boolean(pstate, expr, "CHECK");
3055 
3056  /*
3057  * Fix up collation information.
3058  */
3059  assign_expr_collations(pstate, expr);
3060 
3061  /*
3062  * Domains don't allow variables (this is probably dead code now that
3063  * add_missing_from is history, but let's be sure).
3064  */
3065  if (list_length(pstate->p_rtable) != 0 ||
3066  contain_var_clause(expr))
3067  ereport(ERROR,
3068  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
3069  errmsg("cannot use table references in domain check constraint")));
3070 
3071  /*
3072  * Convert to string form for storage.
3073  */
3074  ccbin = nodeToString(expr);
3075 
3076  /*
3077  * Store the constraint in pg_constraint
3078  */
3079  ccoid =
3080  CreateConstraintEntry(constr->conname, /* Constraint Name */
3081  domainNamespace, /* namespace */
3082  CONSTRAINT_CHECK, /* Constraint Type */
3083  false, /* Is Deferrable */
3084  false, /* Is Deferred */
3085  !constr->skip_validation, /* Is Validated */
3086  InvalidOid, /* no parent constraint */
3087  InvalidOid, /* not a relation constraint */
3088  NULL,
3089  0,
3090  0,
3091  domainOid, /* domain constraint */
3092  InvalidOid, /* no associated index */
3093  InvalidOid, /* Foreign key fields */
3094  NULL,
3095  NULL,
3096  NULL,
3097  NULL,
3098  0,
3099  ' ',
3100  ' ',
3101  ' ',
3102  NULL, /* not an exclusion constraint */
3103  expr, /* Tree form of check constraint */
3104  ccbin, /* Binary form of check constraint */
3105  true, /* is local */
3106  0, /* inhcount */
3107  false, /* connoinherit */
3108  false); /* is_internal */
3109  if (constrAddr)
3110  ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
3111 
3112  /*
3113  * Return the compiled constraint expression so the calling routine can
3114  * perform any additional required tests.
3115  */
3116  return ccbin;
3117 }
#define NIL
Definition: pg_list.h:65
char * ChooseConstraintName(const char *name1, const char *name2, const char *label, Oid namespaceid, List *others)
bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, const char *conname)
static Node * replace_domain_constraint_value(ParseState *pstate, ColumnRef *cref)
Definition: typecmds.c:3121
Oid CreateConstraintEntry(const char *constraintName, Oid constraintNamespace, char constraintType, bool isDeferrable, bool isDeferred, bool isValidated, Oid parentConstrId, Oid relId, const int16 *constraintKey, int constraintNKeys, int constraintNTotalKeys, Oid domainId, Oid indexRelId, Oid foreignRelId, const int16 *foreignKey, const Oid *pfEqOp, const Oid *ppEqOp, const Oid *ffEqOp, int foreignNKeys, char foreignUpdateType, char foreignDeleteType, char foreignMatchType, const Oid *exclOp, Node *conExpr, const char *conBin, bool conIsLocal, int conInhCount, bool conNoInherit, bool is_internal)
Definition: pg_constraint.c:50
Node * raw_expr
Definition: parsenodes.h:2162
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:145
Definition: nodes.h:529
int errcode(int sqlerrcode)
Definition: elog.c:610
bool contain_var_clause(Node *node)
Definition: var.c:331
char * conname
Definition: parsenodes.h:2155
unsigned int Oid
Definition: postgres_ext.h:31
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
void assign_expr_collations(ParseState *pstate, Node *expr)
#define ERROR
Definition: elog.h:43
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:2933
#define makeNode(_type_)
Definition: nodes.h:577
void * p_ref_hook_state
Definition: parse_node.h:222
static int list_length(const List *l)
Definition: pg_list.h:169
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
int errmsg(const char *fmt,...)
Definition: elog.c:824
char * nodeToString(const void *obj)
Definition: outfuncs.c:4360
PreParseColumnRefHook p_pre_columnref_hook
Definition: parse_node.h:218
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
bool skip_validation
Definition: parsenodes.h:2197
List * p_rtable
Definition: parse_node.h:180
Node * coerce_to_boolean(ParseState *pstate, Node *node, const char *constructName)

◆ findRangeCanonicalFunction()

static Oid findRangeCanonicalFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 1932 of file typecmds.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, ereport, errcode(), errmsg(), ERROR, func_signature_string(), func_volatile(), get_func_name(), get_func_rettype(), GetUserId(), LookupFuncName(), NIL, OBJECT_FUNCTION, OidIsValid, and pg_proc_aclcheck().

Referenced by DefineRange().

1933 {
1934  Oid argList[1];
1935  Oid procOid;
1936  AclResult aclresult;
1937 
1938  /*
1939  * Range canonical functions must take and return the range type, and must
1940  * be immutable.
1941  */
1942  argList[0] = typeOid;
1943 
1944  procOid = LookupFuncName(procname, 1, argList, true);
1945 
1946  if (!OidIsValid(procOid))
1947  ereport(ERROR,
1948  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1949  errmsg("function %s does not exist",
1950  func_signature_string(procname, 1, NIL, argList))));
1951 
1952  if (get_func_rettype(procOid) != typeOid)
1953  ereport(ERROR,
1954  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1955  errmsg("range canonical function %s must return range type",
1956  func_signature_string(procname, 1, NIL, argList))));
1957 
1958  if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
1959  ereport(ERROR,
1960  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1961  errmsg("range canonical function %s must be immutable",
1962  func_signature_string(procname, 1, NIL, argList))));
1963 
1964  /* Also, range type's creator must have permission to call function */
1965  aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
1966  if (aclresult != ACLCHECK_OK)
1967  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
1968 
1969  return procOid;
1970 }
#define NIL
Definition: pg_list.h:65
Oid GetUserId(void)
Definition: miscinit.c:448
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1567
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1520
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2103
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2015
AclResult
Definition: acl.h:177
#define ereport(elevel,...)
Definition: elog.h:144
char func_volatile(Oid funcid)
Definition: lsyscache.c:1692
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define ACL_EXECUTE
Definition: parsenodes.h:81
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4587

◆ findRangeSubOpclass()

static Oid findRangeSubOpclass ( List opcname,
Oid  subtype 
)
static

Definition at line 1893 of file typecmds.c.

References ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), get_opclass_input_type(), get_opclass_oid(), GetDefaultOpClass(), IsBinaryCoercible(), NameListToString(), NIL, and OidIsValid.

Referenced by DefineRange().

1894 {
1895  Oid opcid;
1896  Oid opInputType;
1897 
1898  if (opcname != NIL)
1899  {
1900  opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
1901 
1902  /*
1903  * Verify that the operator class accepts this datatype. Note we will
1904  * accept binary compatibility.
1905  */
1906  opInputType = get_opclass_input_type(opcid);
1907  if (!IsBinaryCoercible(subtype, opInputType))
1908  ereport(ERROR,
1909  (errcode(ERRCODE_DATATYPE_MISMATCH),
1910  errmsg("operator class \"%s\" does not accept data type %s",
1911  NameListToString(opcname),
1912  format_type_be(subtype))));
1913  }
1914  else
1915  {
1916  opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
1917  if (!OidIsValid(opcid))
1918  {
1919  /* We spell the error message identically to ResolveOpClass */
1920  ereport(ERROR,
1921  (errcode(ERRCODE_UNDEFINED_OBJECT),
1922  errmsg("data type %s has no default operator class for access method \"%s\"",
1923  format_type_be(subtype), "btree"),
1924  errhint("You must specify an operator class for the range type or define a default operator class for the subtype.")));
1925  }
1926  }
1927 
1928  return opcid;
1929 }
#define NIL
Definition: pg_list.h:65
int errhint(const char *fmt,...)
Definition: elog.c:1071
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:2045
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
Definition: opclasscmds.c:223
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
#define ERROR
Definition: elog.h:43
bool IsBinaryCoercible(Oid srctype, Oid targettype)
char * NameListToString(List *names)
Definition: namespace.c:3102
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1151

◆ findRangeSubtypeDiffFunction()

static Oid findRangeSubtypeDiffFunction ( List procname,
Oid  subtype 
)
static

Definition at line 1973 of file typecmds.c.

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, ereport, errcode(), errmsg(), ERROR, func_signature_string(), func_volatile(), get_func_name(), get_func_rettype(), GetUserId(), LookupFuncName(), NIL, OBJECT_FUNCTION, OidIsValid, and pg_proc_aclcheck().

Referenced by DefineRange().

1974 {
1975  Oid argList[2];
1976  Oid procOid;
1977  AclResult aclresult;
1978 
1979  /*
1980  * Range subtype diff functions must take two arguments of the subtype,
1981  * must return float8, and must be immutable.
1982  */
1983  argList[0] = subtype;
1984  argList[1] = subtype;
1985 
1986  procOid = LookupFuncName(procname, 2, argList, true);
1987 
1988  if (!OidIsValid(procOid))
1989  ereport(ERROR,
1990  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1991  errmsg("function %s does not exist",
1992  func_signature_string(procname, 2, NIL, argList))));
1993 
1994  if (get_func_rettype(procOid) != FLOAT8OID)
1995  ereport(ERROR,
1996  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1997  errmsg("range subtype diff function %s must return type %s",
1998  func_signature_string(procname, 2, NIL, argList),
1999  "double precision")));
2000 
2001  if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
2002  ereport(ERROR,
2003  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2004  errmsg("range subtype diff function %s must be immutable",
2005  func_signature_string(procname, 2, NIL, argList))));
2006 
2007  /* Also, range type's creator must have permission to call function */
2008  aclresult = pg_proc_aclcheck(procOid, GetUserId(), ACL_EXECUTE);
2009  if (aclresult != ACLCHECK_OK)
2010  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(procOid));
2011 
2012  return procOid;
2013 }
#define NIL
Definition: pg_list.h:65
Oid GetUserId(void)
Definition: miscinit.c:448
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1567
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1520
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2103
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2015
AclResult
Definition: acl.h:177
#define ereport(elevel,...)
Definition: elog.h:144
char func_volatile(Oid funcid)
Definition: lsyscache.c:1692
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define ACL_EXECUTE
Definition: parsenodes.h:81
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4587

◆ findTypeAnalyzeFunction()

static Oid findTypeAnalyzeFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 1858 of file typecmds.c.

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

Referenced by AlterType(), and DefineType().

1859 {
1860  Oid argList[1];
1861  Oid procOid;
1862 
1863  /*
1864  * Analyze functions always take one INTERNAL argument and return bool.
1865  */
1866  argList[0] = INTERNALOID;
1867 
1868  procOid = LookupFuncName(procname, 1, argList, true);
1869  if (!OidIsValid(procOid))
1870  ereport(ERROR,
1871  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1872  errmsg("function %s does not exist",
1873  func_signature_string(procname, 1, NIL, argList))));
1874 
1875  if (get_func_rettype(procOid) != BOOLOID)
1876  ereport(ERROR,
1877  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1878  errmsg("type analyze function %s must return type %s",
1879  NameListToString(procname), "boolean")));
1880 
1881  return procOid;
1882 }
#define NIL
Definition: pg_list.h:65
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1567
#define ERROR
Definition: elog.h:43
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2103
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2015
char * NameListToString(List *names)
Definition: namespace.c:3102
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ findTypeInputFunction()

static Oid findTypeInputFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 1625 of file typecmds.c.

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

Referenced by DefineType().

1626 {
1627  Oid argList[3];
1628  Oid procOid;
1629 
1630  /*
1631  * Input functions can take a single argument of type CSTRING, or three
1632  * arguments (string, typioparam OID, typmod). They must return the
1633  * target type.
1634  */
1635  argList[0] = CSTRINGOID;
1636 
1637  procOid = LookupFuncName(procname, 1, argList, true);
1638  if (!OidIsValid(procOid))
1639  {
1640  argList[1] = OIDOID;
1641  argList[2] = INT4OID;
1642 
1643  procOid = LookupFuncName(procname, 3, argList, true);
1644  if (!OidIsValid(procOid))
1645  ereport(ERROR,
1646  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1647  errmsg("function %s does not exist",
1648  func_signature_string(procname, 1, NIL, argList))));
1649  }
1650 
1651  if (get_func_rettype(procOid) != typeOid)
1652  ereport(ERROR,
1653  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1654  errmsg("type input function %s must return type %s",
1655  NameListToString(procname), format_type_be(typeOid))));
1656 
1657  /*
1658  * Print warnings if any of the type's I/O functions are marked volatile.
1659  * There is a general assumption that I/O functions are stable or
1660  * immutable; this allows us for example to mark record_in/record_out
1661  * stable rather than volatile. Ideally we would throw errors not just
1662  * warnings here; but since this check is new as of 9.5, and since the
1663  * volatility marking might be just an error-of-omission and not a true
1664  * indication of how the function behaves, we'll let it pass as a warning
1665  * for now.
1666  */
1667  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
1668  ereport(WARNING,
1669  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1670  errmsg("type input function %s should not be volatile",
1671  NameListToString(procname))));
1672 
1673  return procOid;
1674 }
#define NIL
Definition: pg_list.h:65
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1567
#define ERROR
Definition: elog.h:43
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2103
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2015
#define WARNING
Definition: elog.h:40
char * NameListToString(List *names)
Definition: namespace.c:3102
#define ereport(elevel,...)
Definition: elog.h:144
char func_volatile(Oid funcid)
Definition: lsyscache.c:1692
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ findTypeOutputFunction()

static Oid findTypeOutputFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 1677 of file typecmds.c.

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

Referenced by DefineType().

1678 {
1679  Oid argList[1];
1680  Oid procOid;
1681 
1682  /*
1683  * Output functions always take a single argument of the type and return
1684  * cstring.
1685  */
1686  argList[0] = typeOid;
1687 
1688  procOid = LookupFuncName(procname, 1, argList, true);
1689  if (!OidIsValid(procOid))
1690  ereport(ERROR,
1691  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1692  errmsg("function %s does not exist",
1693  func_signature_string(procname, 1, NIL, argList))));
1694 
1695  if (get_func_rettype(procOid) != CSTRINGOID)
1696  ereport(ERROR,
1697  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1698  errmsg("type output function %s must return type %s",
1699  NameListToString(procname), "cstring")));
1700 
1701  /* Just a warning for now, per comments in findTypeInputFunction */
1702  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
1703  ereport(WARNING,
1704  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1705  errmsg("type output function %s should not be volatile",
1706  NameListToString(procname))));
1707 
1708  return procOid;
1709 }
#define NIL
Definition: pg_list.h:65
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1567
#define ERROR
Definition: elog.h:43
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2103
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2015
#define WARNING
Definition: elog.h:40
char * NameListToString(List *names)
Definition: namespace.c:3102
#define ereport(elevel,...)
Definition: elog.h:144
char func_volatile(Oid funcid)
Definition: lsyscache.c:1692
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ findTypeReceiveFunction()

static Oid findTypeReceiveFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 1712 of file typecmds.c.

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

Referenced by AlterType(), and DefineType().

1713 {
1714  Oid argList[3];
1715  Oid procOid;
1716 
1717  /*
1718  * Receive functions can take a single argument of type INTERNAL, or three
1719  * arguments (internal, typioparam OID, typmod). They must return the
1720  * target type.
1721  */
1722  argList[0] = INTERNALOID;
1723 
1724  procOid = LookupFuncName(procname, 1, argList, true);
1725  if (!OidIsValid(procOid))
1726  {
1727  argList[1] = OIDOID;
1728  argList[2] = INT4OID;
1729 
1730  procOid = LookupFuncName(procname, 3, argList, true);
1731  if (!OidIsValid(procOid))
1732  ereport(ERROR,
1733  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1734  errmsg("function %s does not exist",
1735  func_signature_string(procname, 1, NIL, argList))));
1736  }
1737 
1738  if (get_func_rettype(procOid) != typeOid)
1739  ereport(ERROR,
1740  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1741  errmsg("type receive function %s must return type %s",
1742  NameListToString(procname), format_type_be(typeOid))));
1743 
1744  /* Just a warning for now, per comments in findTypeInputFunction */
1745  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
1746  ereport(WARNING,
1747  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1748  errmsg("type receive function %s should not be volatile",
1749  NameListToString(procname))));
1750 
1751  return procOid;
1752 }
#define NIL
Definition: pg_list.h:65
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1567
#define ERROR
Definition: elog.h:43
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2103
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2015
#define WARNING
Definition: elog.h:40
char * NameListToString(List *names)
Definition: namespace.c:3102
#define ereport(elevel,...)
Definition: elog.h:144
char func_volatile(Oid funcid)
Definition: lsyscache.c:1692
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ findTypeSendFunction()

static Oid findTypeSendFunction ( List procname,
Oid  typeOid 
)
static

Definition at line 1755 of file typecmds.c.

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

Referenced by AlterType(), and DefineType().

1756 {
1757  Oid argList[1];
1758  Oid procOid;
1759 
1760  /*
1761  * Send functions always take a single argument of the type and return
1762  * bytea.
1763  */
1764  argList[0] = typeOid;
1765 
1766  procOid = LookupFuncName(procname, 1, argList, true);
1767  if (!OidIsValid(procOid))
1768  ereport(ERROR,
1769  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1770  errmsg("function %s does not exist",
1771  func_signature_string(procname, 1, NIL, argList))));
1772 
1773  if (get_func_rettype(procOid) != BYTEAOID)
1774  ereport(ERROR,
1775  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1776  errmsg("type send function %s must return type %s",
1777  NameListToString(procname), "bytea")));
1778 
1779  /* Just a warning for now, per comments in findTypeInputFunction */
1780  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
1781  ereport(WARNING,
1782  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1783  errmsg("type send function %s should not be volatile",
1784  NameListToString(procname))));
1785 
1786  return procOid;
1787 }
#define NIL
Definition: pg_list.h:65
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1567
#define ERROR
Definition: elog.h:43
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2103
const char * func_signature_string(List *funcname, int nargs, List *argnames, const Oid *argtypes)
Definition: parse_func.c:2015
#define WARNING
Definition: elog.h:40
char * NameListToString(List *names)
Definition: namespace.c:3102
#define ereport(elevel,...)
Definition: elog.h:144
char func_volatile(Oid funcid)
Definition: lsyscache.c:1692
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ findTypeTypmodinFunction()

static Oid findTypeTypmodinFunction ( List procname)
static

Definition at line 1790 of file typecmds.c.

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

Referenced by AlterType(), and DefineType().

1791 {
1792  Oid argList[1];
1793  Oid procOid;
1794 
1795  /*
1796  * typmodin functions always take one cstring[] argument and return int4.
1797  */
1798  argList[0] = CSTRINGARRAYOID;
1799 
1800  procOid = LookupFuncName(procname, 1, argList, true);
1801  if (!OidIsValid(procOid))
1802  ereport(ERROR,
1803  (errcode(ERRCODE_UNDEFINED_FUNCTION),
1804  errmsg("function %s does not exist",
1805  func_signature_string(procname, 1, NIL, argList))));
1806 
1807  if (get_func_rettype(procOid) != INT4OID)
1808  ereport(ERROR,
1809  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1810  errmsg("typmod_in function %s must return type %s",
1811  NameListToString(procname), "integer")));
1812 
1813  /* Just a warning for now, per comments in findTypeInputFunction */
1814  if (func_volatile(procOid) == PROVOLATILE_VOLATILE)
1815  ereport(WARNING,
1816  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1817  errmsg("type modifier input function %s should not be volatile",
1818  NameListToString(procname))));
1819 
1820  return procOid;
1821 }
#define NIL
Definition: pg_list.h:65
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1567
#define ERROR
Definition: elog.h:43
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)