#include "access/htup.h"
#include "catalog/dependency.h"
#include "nodes/parsenodes.h"
Go to the source code of this file.
#define DEFAULT_TYPDELIM ',' |
Definition at line 22 of file typecmds.h.
Referenced by AddNewRelationType(), DefineEnum(), DefineRange(), heap_create_with_catalog(), and TypeShellMake().
Definition at line 2408 of file typecmds.c.
References checkDomainOwner(), CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_CHECK, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, domainAddConstraint(), elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, IsA, makeTypeNameFromNameList(), NameStr, nodeTag, NULL, ObjectIdGetDatum, RowExclusiveLock, SearchSysCacheCopy1, Constraint::skip_validation, typenameTypeId(), TYPEOID, TypeRelationId, and validateDomainConstraint().
Referenced by ProcessUtilitySlow().
{ TypeName *typename; Oid domainoid; Relation typrel; HeapTuple tup; Form_pg_type typTup; Constraint *constr; char *ccbin; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); domainoid = typenameTypeId(NULL, typename); /* Look up the domain in the type table */ typrel = heap_open(TypeRelationId, RowExclusiveLock); tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", domainoid); typTup = (Form_pg_type) GETSTRUCT(tup); /* Check it's a domain and check user has permission for ALTER DOMAIN */ checkDomainOwner(tup); if (!IsA(newConstraint, Constraint)) elog(ERROR, "unrecognized node type: %d", (int) nodeTag(newConstraint)); constr = (Constraint *) newConstraint; switch (constr->contype) { case CONSTR_CHECK: /* processed below */ break; case CONSTR_UNIQUE: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unique constraints not possible for domains"))); break; case CONSTR_PRIMARY: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("primary key constraints not possible for domains"))); break; case CONSTR_EXCLUSION: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("exclusion constraints not possible for domains"))); break; case CONSTR_FOREIGN: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("foreign key constraints not possible for domains"))); break; case CONSTR_ATTR_DEFERRABLE: case CONSTR_ATTR_NOT_DEFERRABLE: case CONSTR_ATTR_DEFERRED: case CONSTR_ATTR_IMMEDIATE: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("specifying constraint deferrability not supported for domains"))); break; default: elog(ERROR, "unrecognized constraint subtype: %d", (int) constr->contype); break; } /* * Since all other constraint types throw errors, this must be a check * constraint. First, process the constraint expression and add an entry * to pg_constraint. */ ccbin = domainAddConstraint(domainoid, typTup->typnamespace, typTup->typbasetype, typTup->typtypmod, constr, NameStr(typTup->typname)); /* * If requested to validate the constraint, test all values stored in the * attributes based on the domain the constraint is being added to. */ if (!constr->skip_validation) validateDomainConstraint(domainoid, ccbin); /* Clean up */ heap_close(typrel, RowExclusiveLock); return domainoid; }
Definition at line 2075 of file typecmds.c.
References Anum_pg_type_typdefault, Anum_pg_type_typdefaultbin, CatalogUpdateIndexes(), checkDomainOwner(), cookDefault(), CStringGetTextDatum, deparse_expression(), elog, ERROR, GenerateTypeDependencies(), GETSTRUCT, heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHook, IsA, make_parsestate(), makeTypeNameFromNameList(), MemSet, NameStr, NIL, nodeToString(), NoLock, NULL, ObjectIdGetDatum, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), HeapTupleData::t_self, typenameTypeId(), TYPEOID, and TypeRelationId.
Referenced by ProcessUtilitySlow().
{ TypeName *typename; Oid domainoid; HeapTuple tup; ParseState *pstate; Relation rel; char *defaultValue; Node *defaultExpr = NULL; /* NULL if no default specified */ Datum new_record[Natts_pg_type]; bool new_record_nulls[Natts_pg_type]; bool new_record_repl[Natts_pg_type]; HeapTuple newtuple; Form_pg_type typTup; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); domainoid = typenameTypeId(NULL, typename); /* Look up the domain in the type table */ rel = heap_open(TypeRelationId, RowExclusiveLock); tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", domainoid); typTup = (Form_pg_type) GETSTRUCT(tup); /* Check it's a domain and check user has permission for ALTER DOMAIN */ checkDomainOwner(tup); /* Setup new tuple */ MemSet(new_record, (Datum) 0, sizeof(new_record)); MemSet(new_record_nulls, false, sizeof(new_record_nulls)); MemSet(new_record_repl, false, sizeof(new_record_repl)); /* Store the new default into the tuple */ if (defaultRaw) { /* Create a dummy ParseState for transformExpr */ pstate = make_parsestate(NULL); /* * Cook the colDef->raw_expr into an expression. Note: Name is * strictly for error message */ defaultExpr = cookDefault(pstate, defaultRaw, typTup->typbasetype, typTup->typtypmod, NameStr(typTup->typname)); /* * If the expression is just a NULL constant, we treat the command * like ALTER ... DROP DEFAULT. (But see note for same test in * DefineDomain.) */ if (defaultExpr == NULL || (IsA(defaultExpr, Const) &&((Const *) defaultExpr)->constisnull)) { /* Default is NULL, drop it */ new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true; new_record_repl[Anum_pg_type_typdefaultbin - 1] = true; new_record_nulls[Anum_pg_type_typdefault - 1] = true; new_record_repl[Anum_pg_type_typdefault - 1] = true; } else { /* * Expression must be stored as a nodeToString result, but we also * require a valid textual representation (mainly to make life * easier for pg_dump). */ defaultValue = deparse_expression(defaultExpr, NIL, false, false); /* * Form an updated tuple with the new default and write it back. */ new_record[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(nodeToString(defaultExpr)); new_record_repl[Anum_pg_type_typdefaultbin - 1] = true; new_record[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultValue); new_record_repl[Anum_pg_type_typdefault - 1] = true; } } else { /* ALTER ... DROP DEFAULT */ new_record_nulls[Anum_pg_type_typdefaultbin - 1] = true; new_record_repl[Anum_pg_type_typdefaultbin - 1] = true; new_record_nulls[Anum_pg_type_typdefault - 1] = true; new_record_repl[Anum_pg_type_typdefault - 1] = true; } newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), new_record, new_record_nulls, new_record_repl); simple_heap_update(rel, &tup->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); /* Rebuild dependencies */ GenerateTypeDependencies(typTup->typnamespace, domainoid, InvalidOid, /* typrelid is n/a */ 0, /* relation kind is n/a */ typTup->typowner, typTup->typinput, typTup->typoutput, typTup->typreceive, typTup->typsend, typTup->typmodin, typTup->typmodout, typTup->typanalyze, InvalidOid, false, /* a domain isn't an implicit array */ typTup->typbasetype, typTup->typcollation, defaultExpr, true); /* Rebuild is true */ InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0); /* Clean up */ heap_close(rel, NoLock); heap_freetuple(newtuple); return domainoid; }
Oid AlterDomainDropConstraint | ( | List * | names, | |
const char * | constrName, | |||
DropBehavior | behavior, | |||
bool | missing_ok | |||
) |
Definition at line 2322 of file typecmds.c.
References Anum_pg_constraint_contypid, BTEqualStrategyNumber, checkDomainOwner(), ObjectAddress::classId, ConstraintRelationId, ConstraintTypidIndexId, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, makeTypeNameFromNameList(), NameStr, NoLock, NOTICE, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, performDeletion(), RowExclusiveLock, ScanKeyInit(), SearchSysCacheCopy1, SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), TypeNameToString(), typenameTypeId(), TYPEOID, and TypeRelationId.
Referenced by ProcessUtilitySlow().
{ TypeName *typename; Oid domainoid; HeapTuple tup; Relation rel; Relation conrel; SysScanDesc conscan; ScanKeyData key[1]; HeapTuple contup; bool found = false; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); domainoid = typenameTypeId(NULL, typename); /* Look up the domain in the type table */ rel = heap_open(TypeRelationId, RowExclusiveLock); tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", domainoid); /* Check it's a domain and check user has permission for ALTER DOMAIN */ checkDomainOwner(tup); /* Grab an appropriate lock on the pg_constraint relation */ conrel = heap_open(ConstraintRelationId, RowExclusiveLock); /* Use the index to scan only constraints of the target relation */ ScanKeyInit(&key[0], Anum_pg_constraint_contypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(HeapTupleGetOid(tup))); conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true, SnapshotNow, 1, key); /* * Scan over the result set, removing any matching entries. */ while ((contup = systable_getnext(conscan)) != NULL) { Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup); if (strcmp(NameStr(con->conname), constrName) == 0) { ObjectAddress conobj; conobj.classId = ConstraintRelationId; conobj.objectId = HeapTupleGetOid(contup); conobj.objectSubId = 0; performDeletion(&conobj, behavior, 0); found = true; } } /* Clean up after the scan */ systable_endscan(conscan); heap_close(conrel, RowExclusiveLock); heap_close(rel, NoLock); if (!found) { if (!missing_ok) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("constraint \"%s\" of domain \"%s\" does not exist", constrName, TypeNameToString(typename)))); else ereport(NOTICE, (errmsg("constraint \"%s\" of domain \"%s\" does not exist, skipping", constrName, TypeNameToString(typename)))); } return domainoid; }
Definition at line 2211 of file typecmds.c.
References tupleDesc::attrs, RelToCheck::atts, CatalogUpdateIndexes(), checkDomainOwner(), elog, ereport, errcode(), errmsg(), ERROR, errtablecol(), ForwardScanDirection, get_rels_with_domain(), GETSTRUCT, heap_attisnull(), heap_beginscan(), heap_close, heap_endscan(), heap_freetuple(), heap_getnext(), heap_open(), HeapTupleIsValid, i, InvokeObjectPostAlterHook, lfirst, makeTypeNameFromNameList(), NameStr, RelToCheck::natts, NoLock, NULL, ObjectIdGetDatum, RelToCheck::rel, RelationGetDescr, RelationGetRelationName, RowExclusiveLock, SearchSysCacheCopy1, ShareLock, simple_heap_update(), SnapshotNow, HeapTupleData::t_self, typenameTypeId(), TYPEOID, and TypeRelationId.
Referenced by ProcessUtilitySlow().
{ TypeName *typename; Oid domainoid; Relation typrel; HeapTuple tup; Form_pg_type typTup; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); domainoid = typenameTypeId(NULL, typename); /* Look up the domain in the type table */ typrel = heap_open(TypeRelationId, RowExclusiveLock); tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(domainoid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", domainoid); typTup = (Form_pg_type) GETSTRUCT(tup); /* Check it's a domain and check user has permission for ALTER DOMAIN */ checkDomainOwner(tup); /* Is the domain already set to the desired constraint? */ if (typTup->typnotnull == notNull) { heap_close(typrel, RowExclusiveLock); return InvalidOid; } /* Adding a NOT NULL constraint requires checking existing columns */ if (notNull) { List *rels; ListCell *rt; /* Fetch relation list with attributes based on this domain */ /* ShareLock is sufficient to prevent concurrent data changes */ rels = get_rels_with_domain(domainoid, ShareLock); foreach(rt, rels) { RelToCheck *rtc = (RelToCheck *) lfirst(rt); Relation testrel = rtc->rel; TupleDesc tupdesc = RelationGetDescr(testrel); HeapScanDesc scan; HeapTuple tuple; /* Scan all tuples in this relation */ scan = heap_beginscan(testrel, SnapshotNow, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { int i; /* Test attributes that are of the domain */ for (i = 0; i < rtc->natts; i++) { int attnum = rtc->atts[i]; if (heap_attisnull(tuple, attnum)) { /* * In principle the auxiliary information for this * error should be errdatatype(), but errtablecol() * seems considerably more useful in practice. Since * this code only executes in an ALTER DOMAIN command, * the client should already know which domain is in * question. */ ereport(ERROR, (errcode(ERRCODE_NOT_NULL_VIOLATION), errmsg("column \"%s\" of table \"%s\" contains null values", NameStr(tupdesc->attrs[attnum - 1]->attname), RelationGetRelationName(testrel)), errtablecol(testrel, attnum))); } } } heap_endscan(scan); /* Close each rel after processing, but keep lock */ heap_close(testrel, NoLock); } } /* * Okay to update pg_type row. We can scribble on typTup because it's a * copy. */ typTup->typnotnull = notNull; simple_heap_update(typrel, &tup->t_self, tup); CatalogUpdateIndexes(typrel, tup); InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0); /* Clean up */ heap_freetuple(tup); heap_close(typrel, RowExclusiveLock); return domainoid; }
Definition at line 2513 of file typecmds.c.
References AccessShareLock, Anum_pg_constraint_conbin, Anum_pg_constraint_contypid, BTEqualStrategyNumber, CatalogUpdateIndexes(), checkDomainOwner(), CONSTRAINT_CHECK, ConstraintRelationId, ConstraintTypidIndexId, CONSTROID, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_close, heap_copytuple(), heap_freetuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostAlterHook, makeTypeNameFromNameList(), NameStr, NULL, ObjectIdGetDatum, ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1, simple_heap_update(), SnapshotNow, SysCacheGetAttr(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, TextDatumGetCString, TypeNameToString(), typenameTypeId(), TYPEOID, TypeRelationId, val, and validateDomainConstraint().
Referenced by ProcessUtilitySlow().
{ TypeName *typename; Oid domainoid; Relation typrel; Relation conrel; HeapTuple tup; Form_pg_constraint con = NULL; Form_pg_constraint copy_con; char *conbin; SysScanDesc scan; Datum val; bool found = false; bool isnull; HeapTuple tuple; HeapTuple copyTuple; ScanKeyData key; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); domainoid = typenameTypeId(NULL, typename); /* Look up the domain in the type table */ typrel = heap_open(TypeRelationId, AccessShareLock); tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainoid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", domainoid); /* Check it's a domain and check user has permission for ALTER DOMAIN */ checkDomainOwner(tup); /* * Find and check the target constraint */ conrel = heap_open(ConstraintRelationId, RowExclusiveLock); ScanKeyInit(&key, Anum_pg_constraint_contypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(domainoid)); scan = systable_beginscan(conrel, ConstraintTypidIndexId, true, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(scan))) { con = (Form_pg_constraint) GETSTRUCT(tuple); if (strcmp(NameStr(con->conname), constrName) == 0) { found = true; break; } } if (!found) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("constraint \"%s\" of domain \"%s\" does not exist", constrName, TypeNameToString(typename)))); if (con->contype != CONSTRAINT_CHECK) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("constraint \"%s\" of domain \"%s\" is not a check constraint", constrName, TypeNameToString(typename)))); val = SysCacheGetAttr(CONSTROID, tuple, Anum_pg_constraint_conbin, &isnull); if (isnull) elog(ERROR, "null conbin for constraint %u", HeapTupleGetOid(tuple)); conbin = TextDatumGetCString(val); validateDomainConstraint(domainoid, conbin); /* * Now update the catalog, while we have the door open. */ copyTuple = heap_copytuple(tuple); copy_con = (Form_pg_constraint) GETSTRUCT(copyTuple); copy_con->convalidated = true; simple_heap_update(conrel, ©Tuple->t_self, copyTuple); CatalogUpdateIndexes(conrel, copyTuple); InvokeObjectPostAlterHook(ConstraintRelationId, HeapTupleGetOid(copyTuple), 0); heap_freetuple(copyTuple); systable_endscan(scan); heap_close(typrel, AccessShareLock); heap_close(conrel, RowExclusiveLock); ReleaseSysCache(tup); return domainoid; }
Oid AlterEnum | ( | AlterEnumStmt * | stmt, | |
bool | isTopLevel | |||
) |
Definition at line 1177 of file typecmds.c.
References AddEnumLabel(), checkEnumOwner(), elog, ERROR, GetCurrentTransactionId(), HEAP_UPDATED, HeapTupleHeaderGetXmin, HeapTupleIsValid, InvokeObjectPostAlterHook, makeTypeNameFromNameList(), AlterEnumStmt::newVal, AlterEnumStmt::newValIsAfter, AlterEnumStmt::newValNeighbor, NULL, ObjectIdGetDatum, PreventTransactionChain(), ReleaseSysCache(), SearchSysCache1, AlterEnumStmt::skipIfExists, HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, AlterEnumStmt::typeName, typenameTypeId(), TYPEOID, and TypeRelationId.
Referenced by ProcessUtilitySlow().
{ Oid enum_type_oid; TypeName *typename; HeapTuple tup; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(stmt->typeName); enum_type_oid = typenameTypeId(NULL, typename); tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", enum_type_oid); /* * Ordinarily we disallow adding values within transaction blocks, because * we can't cope with enum OID values getting into indexes and then having * their defining pg_enum entries go away. However, it's okay if the enum * type was created in the current transaction, since then there can be * no such indexes that wouldn't themselves go away on rollback. (We * support this case because pg_dump --binary-upgrade needs it.) We test * this by seeing if the pg_type row has xmin == current XID and is not * HEAP_UPDATED. If it is HEAP_UPDATED, we can't be sure whether the * type was created or only modified in this xact. So we are disallowing * some cases that could theoretically be safe; but fortunately pg_dump * only needs the simplest case. */ if (HeapTupleHeaderGetXmin(tup->t_data) == GetCurrentTransactionId() && !(tup->t_data->t_infomask & HEAP_UPDATED)) /* safe to do inside transaction block */ ; else PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD"); /* Check it's an enum and check user has permission to ALTER the enum */ checkEnumOwner(tup); /* Add the new label */ AddEnumLabel(enum_type_oid, stmt->newVal, stmt->newValNeighbor, stmt->newValIsAfter, stmt->skipIfExists); InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0); ReleaseSysCache(tup); return enum_type_oid; }
Oid AlterTypeNamespace | ( | List * | names, | |
const char * | newschema, | |||
ObjectType | objecttype | |||
) |
Definition at line 3395 of file typecmds.c.
References AlterTypeNamespace_oid(), ereport, errcode(), errmsg(), ERROR, format_type_be(), free_object_addresses(), get_typtype(), LookupCreationNamespace(), makeTypeNameFromNameList(), new_object_addresses(), NULL, OBJECT_DOMAIN, typenameTypeId(), and TYPTYPE_DOMAIN.
Referenced by ExecAlterObjectSchemaStmt().
{ TypeName *typename; Oid typeOid; Oid nspOid; ObjectAddresses *objsMoved; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); typeOid = typenameTypeId(NULL, typename); /* Don't allow ALTER DOMAIN on a type */ if (objecttype == OBJECT_DOMAIN && get_typtype(typeOid) != TYPTYPE_DOMAIN) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("%s is not a domain", format_type_be(typeOid)))); /* get schema OID and check its permissions */ nspOid = LookupCreationNamespace(newschema); objsMoved = new_object_addresses(); AlterTypeNamespace_oid(typeOid, nspOid, objsMoved); free_object_addresses(objsMoved); return typeOid; }
Oid AlterTypeNamespace_oid | ( | Oid | typeOid, | |
Oid | nspOid, | |||
ObjectAddresses * | objsMoved | |||
) |
Definition at line 3424 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().
{ Oid elemOid; /* check permissions on type */ if (!pg_type_ownercheck(typeOid, GetUserId())) aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid); /* don't allow direct alteration of array types */ elemOid = get_element_type(typeOid); if (OidIsValid(elemOid) && get_array_type(elemOid) == typeOid) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot alter array type %s", format_type_be(typeOid)), errhint("You can alter type %s, which will alter the array type as well.", format_type_be(elemOid)))); /* and do the work */ return AlterTypeNamespaceInternal(typeOid, nspOid, false, true, objsMoved); }
Oid AlterTypeNamespaceInternal | ( | Oid | typeOid, | |
Oid | nspOid, | |||
bool | isImplicitArray, | |||
bool | errorOnTableType, | |||
ObjectAddresses * | objsMoved | |||
) |
Definition at line 3462 of file typecmds.c.
References add_exact_object_address(), AlterConstraintNamespaces(), AlterRelationNamespaceInternal(), AlterTypeNamespaceInternal(), CatalogUpdateIndexes(), changeDependencyFor(), CheckSetNamespace(), ObjectAddress::classId, CStringGetDatum, elog, ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), get_namespace_name(), get_rel_relkind(), GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, InvokeObjectPostAlterHook, NamespaceRelationId, NameStr, object_address_present(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, RelationRelationId, RowExclusiveLock, SearchSysCacheCopy1, SearchSysCacheExists2, simple_heap_update(), HeapTupleData::t_self, TYPENAMENSP, TYPEOID, TypeRelationId, TYPTYPE_COMPOSITE, and TYPTYPE_DOMAIN.
Referenced by AlterSeqNamespaces(), AlterTableNamespaceInternal(), AlterTypeNamespace_oid(), and AlterTypeNamespaceInternal().
{ Relation rel; HeapTuple tup; Form_pg_type typform; Oid oldNspOid; Oid arrayOid; bool isCompositeType; ObjectAddress thisobj; /* * Make sure we haven't moved this object previously. */ thisobj.classId = TypeRelationId; thisobj.objectId = typeOid; thisobj.objectSubId = 0; if (object_address_present(&thisobj, objsMoved)) return InvalidOid; rel = heap_open(TypeRelationId, RowExclusiveLock); tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", typeOid); typform = (Form_pg_type) GETSTRUCT(tup); oldNspOid = typform->typnamespace; arrayOid = typform->typarray; /* common checks on switching namespaces */ CheckSetNamespace(oldNspOid, nspOid, TypeRelationId, typeOid); /* check for duplicate name (more friendly than unique-index failure) */ if (SearchSysCacheExists2(TYPENAMENSP, CStringGetDatum(NameStr(typform->typname)), ObjectIdGetDatum(nspOid))) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists in schema \"%s\"", NameStr(typform->typname), get_namespace_name(nspOid)))); /* Detect whether type is a composite type (but not a table rowtype) */ isCompositeType = (typform->typtype == TYPTYPE_COMPOSITE && get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE); /* Enforce not-table-type if requested */ if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType && errorOnTableType) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("%s is a table's row type", format_type_be(typeOid)), errhint("Use ALTER TABLE instead."))); /* OK, modify the pg_type row */ /* tup is a copy, so we can scribble directly on it */ typform->typnamespace = nspOid; simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); /* * Composite types have pg_class entries. * * We need to modify the pg_class tuple as well to reflect the change of * schema. */ if (isCompositeType) { Relation classRel; classRel = heap_open(RelationRelationId, RowExclusiveLock); AlterRelationNamespaceInternal(classRel, typform->typrelid, oldNspOid, nspOid, false, objsMoved); heap_close(classRel, RowExclusiveLock); /* * Check for constraints associated with the composite type (we don't * currently support this, but probably will someday). */ AlterConstraintNamespaces(typform->typrelid, oldNspOid, nspOid, false, objsMoved); } else { /* If it's a domain, it might have constraints */ if (typform->typtype == TYPTYPE_DOMAIN) AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true, objsMoved); } /* * Update dependency on schema, if any --- a table rowtype has not got * one, and neither does an implicit array. */ if ((isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) && !isImplicitArray) if (changeDependencyFor(TypeRelationId, typeOid, NamespaceRelationId, oldNspOid, nspOid) != 1) elog(ERROR, "failed to change schema dependency for type %s", format_type_be(typeOid)); InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0); heap_freetuple(tup); heap_close(rel, RowExclusiveLock); add_exact_object_address(&thisobj, objsMoved); /* Recursively alter the associated array type, if any */ if (OidIsValid(arrayOid)) AlterTypeNamespaceInternal(arrayOid, nspOid, true, true, objsMoved); return oldNspOid; }
Oid AlterTypeOwner | ( | List * | names, | |
Oid | newOwnerId, | |||
ObjectType | objecttype | |||
) |
Definition at line 3218 of file typecmds.c.
References AccessExclusiveLock, ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterTypeOwnerInternal(), ATExecChangeOwner(), CatalogUpdateIndexes(), changeDependencyOnOwner(), check_is_member_of_role(), ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), get_array_type(), get_namespace_name(), get_rel_relkind(), GETSTRUCT, GetUserId(), heap_close, heap_copytuple(), heap_open(), HeapTupleGetOid, InvokeObjectPostAlterHook, LookupTypeName(), makeTypeNameFromNameList(), NULL, OBJECT_DOMAIN, OidIsValid, pg_namespace_aclcheck(), pg_type_ownercheck(), ReleaseSysCache(), RELKIND_COMPOSITE_TYPE, RowExclusiveLock, simple_heap_update(), superuser(), HeapTupleData::t_self, TypeNameToString(), TypeRelationId, typeTypeId(), TYPTYPE_COMPOSITE, and TYPTYPE_DOMAIN.
Referenced by ExecAlterOwnerStmt().
{ TypeName *typename; Oid typeOid; Relation rel; HeapTuple tup; HeapTuple newtup; Form_pg_type typTup; AclResult aclresult; rel = heap_open(TypeRelationId, RowExclusiveLock); /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); /* Use LookupTypeName here so that shell types can be processed */ tup = LookupTypeName(NULL, typename, NULL); if (tup == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(typename)))); typeOid = typeTypeId(tup); /* Copy the syscache entry so we can scribble on it below */ newtup = heap_copytuple(tup); ReleaseSysCache(tup); tup = newtup; typTup = (Form_pg_type) GETSTRUCT(tup); /* Don't allow ALTER DOMAIN on a type */ if (objecttype == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("%s is not a domain", format_type_be(typeOid)))); /* * If it's a composite type, we need to check that it really is a * free-standing composite type, and not a table's rowtype. We want people * to use ALTER TABLE not ALTER TYPE for that case. */ if (typTup->typtype == TYPTYPE_COMPOSITE && get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("%s is a table's row type", format_type_be(typeOid)), errhint("Use ALTER TABLE instead."))); /* don't allow direct alteration of array types, either */ if (OidIsValid(typTup->typelem) && get_array_type(typTup->typelem) == typeOid) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot alter array type %s", format_type_be(typeOid)), errhint("You can alter type %s, which will alter the array type as well.", format_type_be(typTup->typelem)))); /* * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is for dump restoration purposes. */ if (typTup->typowner != newOwnerId) { /* Superusers can always do it */ if (!superuser()) { /* Otherwise, must be owner of the existing object */ if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId())) aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup)); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); /* New owner must have CREATE privilege on namespace */ aclresult = pg_namespace_aclcheck(typTup->typnamespace, newOwnerId, ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(typTup->typnamespace)); } /* * If it's a composite type, invoke ATExecChangeOwner so that we fix * up the pg_class entry properly. That will call back to * AlterTypeOwnerInternal to take care of the pg_type entry(s). */ if (typTup->typtype == TYPTYPE_COMPOSITE) ATExecChangeOwner(typTup->typrelid, newOwnerId, true, AccessExclusiveLock); else { /* * We can just apply the modification directly. * * okay to scribble on typTup because it's a copy */ typTup->typowner = newOwnerId; simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); /* Update owner dependency reference */ changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId); InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0); /* If it has an array type, update that too */ if (OidIsValid(typTup->typarray)) AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false); } } /* Clean up */ heap_close(rel, RowExclusiveLock); return typeOid; }
Definition at line 3354 of file typecmds.c.
References AlterTypeOwnerInternal(), CatalogUpdateIndexes(), changeDependencyOnOwner(), elog, ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, InvokeObjectPostAlterHook, ObjectIdGetDatum, OidIsValid, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), HeapTupleData::t_self, TYPEOID, and TypeRelationId.
Referenced by AlterTypeOwner(), AlterTypeOwnerInternal(), ATExecChangeOwner(), and shdepReassignOwned().
{ Relation rel; HeapTuple tup; Form_pg_type typTup; rel = heap_open(TypeRelationId, RowExclusiveLock); tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", typeOid); typTup = (Form_pg_type) GETSTRUCT(tup); /* * Modify the owner --- okay to scribble on typTup because it's a copy */ typTup->typowner = newOwnerId; simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); /* Update owner dependency reference, if it has one */ if (hasDependEntry) changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId); /* If it has an array type, update that too */ if (OidIsValid(typTup->typarray)) AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false); InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0); /* Clean up */ heap_close(rel, RowExclusiveLock); }
Oid AssignTypeArrayOid | ( | void | ) |
Definition at line 1983 of file typecmds.c.
References AccessShareLock, binary_upgrade_next_array_pg_type_oid, GetNewOid(), heap_close, heap_open(), IsBinaryUpgrade, OidIsValid, and TypeRelationId.
Referenced by DefineEnum(), DefineRange(), DefineType(), and heap_create_with_catalog().
{ Oid type_array_oid; /* Use binary-upgrade override for pg_type.typarray, if supplied. */ if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_array_pg_type_oid)) { type_array_oid = binary_upgrade_next_array_pg_type_oid; binary_upgrade_next_array_pg_type_oid = InvalidOid; } else { Relation pg_type = heap_open(TypeRelationId, AccessShareLock); type_array_oid = GetNewOid(pg_type); heap_close(pg_type, AccessShareLock); } return type_array_oid; }
void checkDomainOwner | ( | HeapTuple | tup | ) |
Definition at line 2874 of file typecmds.c.
References aclcheck_error_type(), ACLCHECK_NOT_OWNER, ereport, errcode(), errmsg(), ERROR, format_type_be(), GETSTRUCT, GetUserId(), HeapTupleGetOid, pg_type_ownercheck(), and TYPTYPE_DOMAIN.
Referenced by AlterDomainAddConstraint(), AlterDomainDefault(), AlterDomainDropConstraint(), AlterDomainNotNull(), AlterDomainValidateConstraint(), and RenameConstraint().
{ Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup); /* Check that this is actually a domain */ if (typTup->typtype != TYPTYPE_DOMAIN) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("%s is not a domain", format_type_be(HeapTupleGetOid(tup))))); /* Permission check: must own type */ if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId())) aclcheck_error_type(ACLCHECK_NOT_OWNER, HeapTupleGetOid(tup)); }
Definition at line 2020 of file typecmds.c.
References Assert, CreateStmt::constraints, CStringGetDatum, DefineRelation(), ereport, errcode(), errmsg(), ERROR, GetSysCacheOid2, CreateStmt::if_not_exists, CreateStmt::inhRelations, InvalidOid, makeNode, moveArrayTypeName(), NoLock, NULL, ObjectIdGetDatum, OidIsValid, CreateStmt::oncommit, CreateStmt::options, RangeVarAdjustRelationPersistence(), RangeVarGetAndCheckCreationNamespace(), CreateStmt::relation, RELKIND_COMPOSITE_TYPE, RangeVar::relname, CreateStmt::tableElts, CreateStmt::tablespacename, and TYPENAMENSP.
Referenced by ProcessUtilitySlow().
{ CreateStmt *createStmt = makeNode(CreateStmt); Oid old_type_oid; Oid typeNamespace; Oid relid; /* * now set the parameters for keys/inheritance etc. All of these are * uninteresting for composite types... */ createStmt->relation = typevar; createStmt->tableElts = coldeflist; createStmt->inhRelations = NIL; createStmt->constraints = NIL; createStmt->options = NIL; createStmt->oncommit = ONCOMMIT_NOOP; createStmt->tablespacename = NULL; createStmt->if_not_exists = false; /* * Check for collision with an existing type name. If there is one and * it's an autogenerated array, we can rename it out of the way. This * check is here mainly to get a better error message about a "type" * instead of below about a "relation". */ typeNamespace = RangeVarGetAndCheckCreationNamespace(createStmt->relation, NoLock, NULL); RangeVarAdjustRelationPersistence(createStmt->relation, typeNamespace); old_type_oid = GetSysCacheOid2(TYPENAMENSP, CStringGetDatum(createStmt->relation->relname), ObjectIdGetDatum(typeNamespace)); if (OidIsValid(old_type_oid)) { if (!moveArrayTypeName(old_type_oid, createStmt->relation->relname, typeNamespace)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists", createStmt->relation->relname))); } /* * Finally create the relation. This also creates the type. */ relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid); Assert(relid != InvalidOid); return relid; }
Oid DefineDomain | ( | CreateDomainStmt * | stmt | ) |
Definition at line 678 of file typecmds.c.
References ACL_CREATE, ACL_KIND_NAMESPACE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, Anum_pg_type_typdefault, Anum_pg_type_typdefaultbin, TypeName::arrayBounds, CreateDomainStmt::collClause, CollateClause::collname, CommandCounterIncrement(), CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_NOTNULL, CONSTR_NULL, CONSTR_PRIMARY, CONSTR_UNIQUE, CreateDomainStmt::constraints, Constraint::contype, cookDefault(), CStringGetDatum, deparse_expression(), domainAddConstraint(), CreateDomainStmt::domainname, elog, ereport, errcode(), errmsg(), ERROR, format_type_be(), get_collation_oid(), get_namespace_name(), GETSTRUCT, GetSysCacheOid2, GetUserId(), HeapTupleGetOid, InvalidOid, Constraint::is_no_inherit, IsA, lfirst, list_length(), make_parsestate(), moveArrayTypeName(), NIL, nodeTag, nodeToString(), NULL, ObjectIdGetDatum, OidIsValid, pg_namespace_aclcheck(), pg_type_aclcheck(), QualifiedNameGetCreationNamespace(), Constraint::raw_expr, ReleaseSysCache(), SysCacheGetAttr(), TextDatumGetCString, TypeCreate(), CreateDomainStmt::typeName, TYPENAMENSP, TypeNameToString(), typenameType(), TYPEOID, TYPTYPE_BASE, TYPTYPE_DOMAIN, TYPTYPE_ENUM, and TYPTYPE_RANGE.
Referenced by ProcessUtilitySlow().
{ char *domainName; Oid domainNamespace; AclResult aclresult; int16 internalLength; Oid inputProcedure; Oid outputProcedure; Oid receiveProcedure; Oid sendProcedure; Oid analyzeProcedure; bool byValue; char category; char delimiter; char alignment; char storage; char typtype; Datum datum; bool isnull; char *defaultValue = NULL; char *defaultValueBin = NULL; bool saw_default = false; bool typNotNull = false; bool nullDefined = false; int32 typNDims = list_length(stmt->typeName->arrayBounds); HeapTuple typeTup; List *schema = stmt->constraints; ListCell *listptr; Oid basetypeoid; Oid domainoid; Oid old_type_oid; Oid domaincoll; Form_pg_type baseType; int32 basetypeMod; Oid baseColl; /* Convert list of names to a name and namespace */ domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname, &domainName); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(domainNamespace)); /* * Check for collision with an existing type name. If there is one and * it's an autogenerated array, we can rename it out of the way. */ old_type_oid = GetSysCacheOid2(TYPENAMENSP, CStringGetDatum(domainName), ObjectIdGetDatum(domainNamespace)); if (OidIsValid(old_type_oid)) { if (!moveArrayTypeName(old_type_oid, domainName, domainNamespace)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists", domainName))); } /* * Look up the base type. */ typeTup = typenameType(NULL, stmt->typeName, &basetypeMod); baseType = (Form_pg_type) GETSTRUCT(typeTup); basetypeoid = HeapTupleGetOid(typeTup); /* * Base type must be a plain base type, another domain, an enum or a range * type. Domains over pseudotypes would create a security hole. Domains * over composite types might be made to work in the future, but not * today. */ typtype = baseType->typtype; if (typtype != TYPTYPE_BASE && typtype != TYPTYPE_DOMAIN && typtype != TYPTYPE_ENUM && typtype != TYPTYPE_RANGE) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("\"%s\" is not a valid base type for a domain", TypeNameToString(stmt->typeName)))); aclresult = pg_type_aclcheck(basetypeoid, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error_type(aclresult, basetypeoid); /* * Identify the collation if any */ baseColl = baseType->typcollation; if (stmt->collClause) domaincoll = get_collation_oid(stmt->collClause->collname, false); else domaincoll = baseColl; /* Complain if COLLATE is applied to an uncollatable type */ if (OidIsValid(domaincoll) && !OidIsValid(baseColl)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("collations are not supported by type %s", format_type_be(basetypeoid)))); /* passed by value */ byValue = baseType->typbyval; /* Required Alignment */ alignment = baseType->typalign; /* TOAST Strategy */ storage = baseType->typstorage; /* Storage Length */ internalLength = baseType->typlen; /* Type Category */ category = baseType->typcategory; /* Array element Delimiter */ delimiter = baseType->typdelim; /* I/O Functions */ inputProcedure = F_DOMAIN_IN; outputProcedure = baseType->typoutput; receiveProcedure = F_DOMAIN_RECV; sendProcedure = baseType->typsend; /* Domains never accept typmods, so no typmodin/typmodout needed */ /* Analysis function */ analyzeProcedure = baseType->typanalyze; /* Inherited default value */ datum = SysCacheGetAttr(TYPEOID, typeTup, Anum_pg_type_typdefault, &isnull); if (!isnull) defaultValue = TextDatumGetCString(datum); /* Inherited default binary value */ datum = SysCacheGetAttr(TYPEOID, typeTup, Anum_pg_type_typdefaultbin, &isnull); if (!isnull) defaultValueBin = TextDatumGetCString(datum); /* * Run through constraints manually to avoid the additional processing * conducted by DefineRelation() and friends. */ foreach(listptr, schema) { Constraint *constr = lfirst(listptr); if (!IsA(constr, Constraint)) elog(ERROR, "unrecognized node type: %d", (int) nodeTag(constr)); switch (constr->contype) { case CONSTR_DEFAULT: /* * The inherited default value may be overridden by the user * with the DEFAULT <expr> clause ... but only once. */ if (saw_default) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple default expressions"))); saw_default = true; if (constr->raw_expr) { ParseState *pstate; Node *defaultExpr; /* Create a dummy ParseState for transformExpr */ pstate = make_parsestate(NULL); /* * Cook the constr->raw_expr into an expression. Note: * name is strictly for error message */ defaultExpr = cookDefault(pstate, constr->raw_expr, basetypeoid, basetypeMod, domainName); /* * If the expression is just a NULL constant, we treat it * like not having a default. * * Note that if the basetype is another domain, we'll see * a CoerceToDomain expr here and not discard the default. * This is critical because the domain default needs to be * retained to override any default that the base domain * might have. */ if (defaultExpr == NULL || (IsA(defaultExpr, Const) && ((Const *) defaultExpr)->constisnull)) { defaultValue = NULL; defaultValueBin = NULL; } else { /* * Expression must be stored as a nodeToString result, * but we also require a valid textual representation * (mainly to make life easier for pg_dump). */ defaultValue = deparse_expression(defaultExpr, NIL, false, false); defaultValueBin = nodeToString(defaultExpr); } } else { /* No default (can this still happen?) */ defaultValue = NULL; defaultValueBin = NULL; } break; case CONSTR_NOTNULL: if (nullDefined && !typNotNull) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting NULL/NOT NULL constraints"))); typNotNull = true; nullDefined = true; break; case CONSTR_NULL: if (nullDefined && typNotNull) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting NULL/NOT NULL constraints"))); typNotNull = false; nullDefined = true; break; case CONSTR_CHECK: /* * Check constraints are handled after domain creation, as * they require the Oid of the domain; at this point we can * only check that they're not marked NO INHERIT, because * that would be bogus. */ if (constr->is_no_inherit) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("check constraints for domains cannot be marked NO INHERIT"))); break; /* * All else are error cases */ case CONSTR_UNIQUE: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unique constraints not possible for domains"))); break; case CONSTR_PRIMARY: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("primary key constraints not possible for domains"))); break; case CONSTR_EXCLUSION: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("exclusion constraints not possible for domains"))); break; case CONSTR_FOREIGN: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("foreign key constraints not possible for domains"))); break; case CONSTR_ATTR_DEFERRABLE: case CONSTR_ATTR_NOT_DEFERRABLE: case CONSTR_ATTR_DEFERRED: case CONSTR_ATTR_IMMEDIATE: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("specifying constraint deferrability not supported for domains"))); break; default: elog(ERROR, "unrecognized constraint subtype: %d", (int) constr->contype); break; } } /* * Have TypeCreate do all the real work. */ domainoid = TypeCreate(InvalidOid, /* no predetermined type OID */ domainName, /* type name */ domainNamespace, /* namespace */ InvalidOid, /* relation oid (n/a here) */ 0, /* relation kind (ditto) */ GetUserId(), /* owner's ID */ internalLength, /* internal size */ TYPTYPE_DOMAIN, /* type-type (domain type) */ category, /* type-category */ false, /* domain types are never preferred */ delimiter, /* array element delimiter */ inputProcedure, /* input procedure */ outputProcedure, /* output procedure */ receiveProcedure, /* receive procedure */ sendProcedure, /* send procedure */ InvalidOid, /* typmodin procedure - none */ InvalidOid, /* typmodout procedure - none */ analyzeProcedure, /* analyze procedure */ InvalidOid, /* no array element type */ false, /* this isn't an array */ InvalidOid, /* no arrays for domains (yet) */ basetypeoid, /* base type ID */ defaultValue, /* default type value (text) */ defaultValueBin, /* default type value (binary) */ byValue, /* passed by value */ alignment, /* required alignment */ storage, /* TOAST strategy */ basetypeMod, /* typeMod value */ typNDims, /* Array dimensions for base type */ typNotNull, /* Type NOT NULL */ domaincoll); /* type's collation */ /* * Process constraints which refer to the domain ID returned by TypeCreate */ foreach(listptr, schema) { Constraint *constr = lfirst(listptr); /* it must be a Constraint, per check above */ switch (constr->contype) { case CONSTR_CHECK: domainAddConstraint(domainoid, domainNamespace, basetypeoid, basetypeMod, constr, domainName); break; /* Other constraint types were fully processed above */ default: break; } /* CCI so we can detect duplicate constraint names */ CommandCounterIncrement(); } /* * Now we can clean up. */ ReleaseSysCache(typeTup); return domainoid; }
Oid DefineEnum | ( | CreateEnumStmt * | stmt | ) |
Definition at line 1056 of file typecmds.c.
References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, AssignTypeArrayOid(), CStringGetDatum, DEFAULT_TYPDELIM, EnumValuesCreate(), ereport, errcode(), errmsg(), ERROR, get_namespace_name(), GetSysCacheOid2, GetUserId(), InvalidOid, makeArrayTypeName(), moveArrayTypeName(), NULL, ObjectIdGetDatum, OidIsValid, pfree(), pg_namespace_aclcheck(), QualifiedNameGetCreationNamespace(), TYPCATEGORY_ARRAY, TYPCATEGORY_ENUM, TypeCreate(), CreateEnumStmt::typeName, TYPENAMENSP, TYPTYPE_BASE, TYPTYPE_ENUM, and CreateEnumStmt::vals.
Referenced by ProcessUtilitySlow().
{ char *enumName; char *enumArrayName; Oid enumNamespace; Oid enumTypeOid; AclResult aclresult; Oid old_type_oid; Oid enumArrayOid; /* Convert list of names to a name and namespace */ enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName, &enumName); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(enumNamespace)); /* * Check for collision with an existing type name. If there is one and * it's an autogenerated array, we can rename it out of the way. */ old_type_oid = GetSysCacheOid2(TYPENAMENSP, CStringGetDatum(enumName), ObjectIdGetDatum(enumNamespace)); if (OidIsValid(old_type_oid)) { if (!moveArrayTypeName(old_type_oid, enumName, enumNamespace)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists", enumName))); } enumArrayOid = AssignTypeArrayOid(); /* Create the pg_type entry */ enumTypeOid = TypeCreate(InvalidOid, /* no predetermined type OID */ enumName, /* type name */ enumNamespace, /* namespace */ InvalidOid, /* relation oid (n/a here) */ 0, /* relation kind (ditto) */ GetUserId(), /* owner's ID */ sizeof(Oid), /* internal size */ TYPTYPE_ENUM, /* type-type (enum type) */ TYPCATEGORY_ENUM, /* type-category (enum type) */ false, /* enum types are never preferred */ DEFAULT_TYPDELIM, /* array element delimiter */ F_ENUM_IN, /* input procedure */ F_ENUM_OUT, /* output procedure */ F_ENUM_RECV, /* receive procedure */ F_ENUM_SEND, /* send procedure */ InvalidOid, /* typmodin procedure - none */ InvalidOid, /* typmodout procedure - none */ InvalidOid, /* analyze procedure - default */ InvalidOid, /* element type ID */ false, /* this is not an array type */ enumArrayOid, /* array type we are about to create */ InvalidOid, /* base type ID (only for domains) */ NULL, /* never a default type value */ NULL, /* binary default isn't sent either */ true, /* always passed by value */ 'i', /* int alignment */ 'p', /* TOAST strategy always plain */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ false, /* Type NOT NULL */ InvalidOid); /* type's collation */ /* Enter the enum's values into pg_enum */ EnumValuesCreate(enumTypeOid, stmt->vals); /* * Create the array type that goes with it. */ enumArrayName = makeArrayTypeName(enumName, enumNamespace); TypeCreate(enumArrayOid, /* force assignment of this type OID */ enumArrayName, /* type name */ enumNamespace, /* namespace */ InvalidOid, /* relation oid (n/a here) */ 0, /* relation kind (ditto) */ GetUserId(), /* owner's ID */ -1, /* internal size (always varlena) */ TYPTYPE_BASE, /* type-type (base type) */ TYPCATEGORY_ARRAY, /* type-category (array) */ false, /* array types are never preferred */ DEFAULT_TYPDELIM, /* array element delimiter */ F_ARRAY_IN, /* input procedure */ F_ARRAY_OUT, /* output procedure */ F_ARRAY_RECV, /* receive procedure */ F_ARRAY_SEND, /* send procedure */ InvalidOid, /* typmodin procedure - none */ InvalidOid, /* typmodout procedure - none */ F_ARRAY_TYPANALYZE, /* analyze procedure */ enumTypeOid, /* element type ID */ true, /* yes this is an array type */ InvalidOid, /* no further array type */ InvalidOid, /* base type ID */ NULL, /* never a default type value */ NULL, /* binary default isn't sent either */ false, /* never passed by value */ 'i', /* enums have align i, so do their arrays */ 'x', /* ARRAY is always toastable */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ false, /* Type NOT NULL */ InvalidOid); /* type's collation */ pfree(enumArrayName); return enumTypeOid; }
Oid DefineRange | ( | CreateRangeStmt * | stmt | ) |
Definition at line 1255 of file typecmds.c.
References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, AssignTypeArrayOid(), CommandCounterIncrement(), CStringGetDatum, DEFAULT_TYPDELIM, defGetQualifiedName(), defGetTypeName(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, findRangeCanonicalFunction(), findRangeSubOpclass(), findRangeSubtypeDiffFunction(), format_type_be(), get_collation_oid(), get_namespace_name(), get_typcollation(), get_typisdefined(), get_typlenbyvalalign(), get_typtype(), GetSysCacheOid2, GetUserId(), InvalidOid, lfirst, makeArrayTypeName(), makeRangeConstructors(), moveArrayTypeName(), NIL, NULL, ObjectIdGetDatum, OidIsValid, CreateRangeStmt::params, pfree(), pg_namespace_aclcheck(), pg_strcasecmp(), QualifiedNameGetCreationNamespace(), RangeCreate(), TYPCATEGORY_ARRAY, TYPCATEGORY_RANGE, type_is_collatable(), TypeCreate(), CreateRangeStmt::typeName, TYPENAMENSP, typenameTypeId(), TypeShellMake(), TYPTYPE_BASE, TYPTYPE_PSEUDO, and TYPTYPE_RANGE.
Referenced by ProcessUtilitySlow().
{ char *typeName; Oid typeNamespace; Oid typoid; char *rangeArrayName; Oid rangeArrayOid; Oid rangeSubtype = InvalidOid; List *rangeSubOpclassName = NIL; List *rangeCollationName = NIL; List *rangeCanonicalName = NIL; List *rangeSubtypeDiffName = NIL; Oid rangeSubOpclass; Oid rangeCollation; regproc rangeCanonical; regproc rangeSubtypeDiff; int16 subtyplen; bool subtypbyval; char subtypalign; char alignment; AclResult aclresult; ListCell *lc; /* Convert list of names to a name and namespace */ typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName, &typeName); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(typeNamespace)); /* * Look to see if type already exists. */ typoid = GetSysCacheOid2(TYPENAMENSP, CStringGetDatum(typeName), ObjectIdGetDatum(typeNamespace)); /* * If it's not a shell, see if it's an autogenerated array type, and if so * rename it out of the way. */ if (OidIsValid(typoid) && get_typisdefined(typoid)) { if (moveArrayTypeName(typoid, typeName, typeNamespace)) typoid = InvalidOid; else ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists", typeName))); } /* * If it doesn't exist, create it as a shell, so that the OID is known for * use in the range function definitions. */ if (!OidIsValid(typoid)) { typoid = TypeShellMake(typeName, typeNamespace, GetUserId()); /* Make new shell type visible for modification below */ CommandCounterIncrement(); } /* Extract the parameters from the parameter list */ foreach(lc, stmt->params) { DefElem *defel = (DefElem *) lfirst(lc); if (pg_strcasecmp(defel->defname, "subtype") == 0) { if (OidIsValid(rangeSubtype)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); /* we can look up the subtype name immediately */ rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel)); } else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0) { if (rangeSubOpclassName != NIL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); rangeSubOpclassName = defGetQualifiedName(defel); } else if (pg_strcasecmp(defel->defname, "collation") == 0) { if (rangeCollationName != NIL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); rangeCollationName = defGetQualifiedName(defel); } else if (pg_strcasecmp(defel->defname, "canonical") == 0) { if (rangeCanonicalName != NIL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); rangeCanonicalName = defGetQualifiedName(defel); } else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0) { if (rangeSubtypeDiffName != NIL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); rangeSubtypeDiffName = defGetQualifiedName(defel); } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("type attribute \"%s\" not recognized", defel->defname))); } /* Must have a subtype */ if (!OidIsValid(rangeSubtype)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("type attribute \"subtype\" is required"))); /* disallow ranges of pseudotypes */ if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("range subtype cannot be %s", format_type_be(rangeSubtype)))); /* Identify subopclass */ rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype); /* Identify collation to use, if any */ if (type_is_collatable(rangeSubtype)) { if (rangeCollationName != NIL) rangeCollation = get_collation_oid(rangeCollationName, false); else rangeCollation = get_typcollation(rangeSubtype); } else { if (rangeCollationName != NIL) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("range collation specified but subtype does not support collation"))); rangeCollation = InvalidOid; } /* Identify support functions, if provided */ if (rangeCanonicalName != NIL) rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName, typoid); else rangeCanonical = InvalidOid; if (rangeSubtypeDiffName != NIL) rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName, rangeSubtype); else rangeSubtypeDiff = InvalidOid; get_typlenbyvalalign(rangeSubtype, &subtyplen, &subtypbyval, &subtypalign); /* alignment must be 'i' or 'd' for ranges */ alignment = (subtypalign == 'd') ? 'd' : 'i'; /* Allocate OID for array type */ rangeArrayOid = AssignTypeArrayOid(); /* Create the pg_type entry */ typoid = TypeCreate(InvalidOid, /* no predetermined type OID */ typeName, /* type name */ typeNamespace, /* namespace */ InvalidOid, /* relation oid (n/a here) */ 0, /* relation kind (ditto) */ GetUserId(), /* owner's ID */ -1, /* internal size (always varlena) */ TYPTYPE_RANGE, /* type-type (range type) */ TYPCATEGORY_RANGE, /* type-category (range type) */ false, /* range types are never preferred */ DEFAULT_TYPDELIM, /* array element delimiter */ F_RANGE_IN, /* input procedure */ F_RANGE_OUT, /* output procedure */ F_RANGE_RECV, /* receive procedure */ F_RANGE_SEND, /* send procedure */ InvalidOid, /* typmodin procedure - none */ InvalidOid, /* typmodout procedure - none */ F_RANGE_TYPANALYZE, /* analyze procedure */ InvalidOid, /* element type ID - none */ false, /* this is not an array type */ rangeArrayOid, /* array type we are about to create */ InvalidOid, /* base type ID (only for domains) */ NULL, /* never a default type value */ NULL, /* no binary form available either */ false, /* never passed by value */ alignment, /* alignment */ 'x', /* TOAST strategy (always extended) */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ false, /* Type NOT NULL */ InvalidOid); /* type's collation (ranges never have one) */ /* Create the entry in pg_range */ RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass, rangeCanonical, rangeSubtypeDiff); /* * Create the array type that goes with it. */ rangeArrayName = makeArrayTypeName(typeName, typeNamespace); TypeCreate(rangeArrayOid, /* force assignment of this type OID */ rangeArrayName, /* type name */ typeNamespace, /* namespace */ InvalidOid, /* relation oid (n/a here) */ 0, /* relation kind (ditto) */ GetUserId(), /* owner's ID */ -1, /* internal size (always varlena) */ TYPTYPE_BASE, /* type-type (base type) */ TYPCATEGORY_ARRAY, /* type-category (array) */ false, /* array types are never preferred */ DEFAULT_TYPDELIM, /* array element delimiter */ F_ARRAY_IN, /* input procedure */ F_ARRAY_OUT, /* output procedure */ F_ARRAY_RECV, /* receive procedure */ F_ARRAY_SEND, /* send procedure */ InvalidOid, /* typmodin procedure - none */ InvalidOid, /* typmodout procedure - none */ F_ARRAY_TYPANALYZE, /* analyze procedure */ typoid, /* element type ID */ true, /* yes this is an array type */ InvalidOid, /* no further array type */ InvalidOid, /* base type ID */ NULL, /* never a default type value */ NULL, /* binary default isn't sent either */ false, /* never passed by value */ alignment, /* alignment - same as range's */ 'x', /* ARRAY is always toastable */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ false, /* Type NOT NULL */ InvalidOid); /* typcollation */ pfree(rangeArrayName); /* And create the constructor functions for this range type */ makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype); return typoid; }
Definition at line 116 of file typecmds.c.
References ACL_CREATE, ACL_KIND_NAMESPACE, ACL_KIND_PROC, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AssignTypeArrayOid(), BYTEAOID, CommandCounterIncrement(), CStringGetDatum, CSTRINGOID, DEFAULT_COLLATION_OID, defGetBoolean(), defGetQualifiedName(), defGetString(), defGetTypeLength(), defGetTypeName(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, findTypeAnalyzeFunction(), findTypeInputFunction(), findTypeOutputFunction(), findTypeReceiveFunction(), findTypeSendFunction(), findTypeTypmodinFunction(), findTypeTypmodoutFunction(), format_type_be(), get_func_rettype(), get_namespace_name(), get_typisdefined(), get_typtype(), GETSTRUCT, GetSysCacheOid2, GetUserId(), InvalidOid, lfirst, makeArrayTypeName(), moveArrayTypeName(), NameListToString(), NIL, NULL, ObjectIdGetDatum, OidIsValid, OPAQUEOID, pfree(), pg_namespace_aclcheck(), pg_proc_ownercheck(), pg_strcasecmp(), QualifiedNameGetCreationNamespace(), ReleaseSysCache(), SetFunctionReturnType(), superuser(), TYPCATEGORY_ARRAY, TypeCreate(), TYPENAMENSP, typenameType(), typenameTypeId(), TypeShellMake(), TYPTYPE_BASE, TYPTYPE_PSEUDO, and WARNING.
Referenced by ProcessUtilitySlow().
{ char *typeName; Oid typeNamespace; int16 internalLength = -1; /* default: variable-length */ List *inputName = NIL; List *outputName = NIL; List *receiveName = NIL; List *sendName = NIL; List *typmodinName = NIL; List *typmodoutName = NIL; List *analyzeName = NIL; char category = TYPCATEGORY_USER; bool preferred = false; char delimiter = DEFAULT_TYPDELIM; Oid elemType = InvalidOid; char *defaultValue = NULL; bool byValue = false; char alignment = 'i'; /* default alignment */ char storage = 'p'; /* default TOAST storage method */ Oid collation = InvalidOid; DefElem *likeTypeEl = NULL; DefElem *internalLengthEl = NULL; DefElem *inputNameEl = NULL; DefElem *outputNameEl = NULL; DefElem *receiveNameEl = NULL; DefElem *sendNameEl = NULL; DefElem *typmodinNameEl = NULL; DefElem *typmodoutNameEl = NULL; DefElem *analyzeNameEl = NULL; DefElem *categoryEl = NULL; DefElem *preferredEl = NULL; DefElem *delimiterEl = NULL; DefElem *elemTypeEl = NULL; DefElem *defaultValueEl = NULL; DefElem *byValueEl = NULL; DefElem *alignmentEl = NULL; DefElem *storageEl = NULL; DefElem *collatableEl = NULL; Oid inputOid; Oid outputOid; Oid receiveOid = InvalidOid; Oid sendOid = InvalidOid; Oid typmodinOid = InvalidOid; Oid typmodoutOid = InvalidOid; Oid analyzeOid = InvalidOid; char *array_type; Oid array_oid; Oid typoid; Oid resulttype; ListCell *pl; /* * As of Postgres 8.4, we require superuser privilege to create a base * type. This is simple paranoia: there are too many ways to mess up the * system with an incorrect type definition (for instance, representation * parameters that don't match what the C code expects). In practice it * takes superuser privilege to create the I/O functions, and so the * former requirement that you own the I/O functions pretty much forced * superuserness anyway. We're just making doubly sure here. * * XXX re-enable NOT_USED code sections below if you remove this test. */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to create a base type"))); /* Convert list of names to a name and namespace */ typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName); #ifdef NOT_USED /* XXX this is unnecessary given the superuser check above */ /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(typeNamespace)); #endif /* * Look to see if type already exists (presumably as a shell; if not, * TypeCreate will complain). */ typoid = GetSysCacheOid2(TYPENAMENSP, CStringGetDatum(typeName), ObjectIdGetDatum(typeNamespace)); /* * If it's not a shell, see if it's an autogenerated array type, and if so * rename it out of the way. */ if (OidIsValid(typoid) && get_typisdefined(typoid)) { if (moveArrayTypeName(typoid, typeName, typeNamespace)) typoid = InvalidOid; } /* * If it doesn't exist, create it as a shell, so that the OID is known for * use in the I/O function definitions. */ if (!OidIsValid(typoid)) { typoid = TypeShellMake(typeName, typeNamespace, GetUserId()); /* Make new shell type visible for modification below */ CommandCounterIncrement(); /* * If the command was a parameterless CREATE TYPE, we're done --- * creating the shell type was all we're supposed to do. */ if (parameters == NIL) return InvalidOid; } else { /* Complain if dummy CREATE TYPE and entry already exists */ if (parameters == NIL) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists", typeName))); } /* Extract the parameters from the parameter list */ foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); DefElem **defelp; if (pg_strcasecmp(defel->defname, "like") == 0) defelp = &likeTypeEl; else if (pg_strcasecmp(defel->defname, "internallength") == 0) defelp = &internalLengthEl; else if (pg_strcasecmp(defel->defname, "input") == 0) defelp = &inputNameEl; else if (pg_strcasecmp(defel->defname, "output") == 0) defelp = &outputNameEl; else if (pg_strcasecmp(defel->defname, "receive") == 0) defelp = &receiveNameEl; else if (pg_strcasecmp(defel->defname, "send") == 0) defelp = &sendNameEl; else if (pg_strcasecmp(defel->defname, "typmod_in") == 0) defelp = &typmodinNameEl; else if (pg_strcasecmp(defel->defname, "typmod_out") == 0) defelp = &typmodoutNameEl; else if (pg_strcasecmp(defel->defname, "analyze") == 0 || pg_strcasecmp(defel->defname, "analyse") == 0) defelp = &analyzeNameEl; else if (pg_strcasecmp(defel->defname, "category") == 0) defelp = &categoryEl; else if (pg_strcasecmp(defel->defname, "preferred") == 0) defelp = &preferredEl; else if (pg_strcasecmp(defel->defname, "delimiter") == 0) defelp = &delimiterEl; else if (pg_strcasecmp(defel->defname, "element") == 0) defelp = &elemTypeEl; else if (pg_strcasecmp(defel->defname, "default") == 0) defelp = &defaultValueEl; else if (pg_strcasecmp(defel->defname, "passedbyvalue") == 0) defelp = &byValueEl; else if (pg_strcasecmp(defel->defname, "alignment") == 0) defelp = &alignmentEl; else if (pg_strcasecmp(defel->defname, "storage") == 0) defelp = &storageEl; else if (pg_strcasecmp(defel->defname, "collatable") == 0) defelp = &collatableEl; else { /* WARNING, not ERROR, for historical backwards-compatibility */ ereport(WARNING, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("type attribute \"%s\" not recognized", defel->defname))); continue; } if (*defelp != NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); *defelp = defel; } /* * Now interpret the options; we do this separately so that LIKE can be * overridden by other options regardless of the ordering in the parameter * list. */ if (likeTypeEl) { Type likeType; Form_pg_type likeForm; likeType = typenameType(NULL, defGetTypeName(likeTypeEl), NULL); likeForm = (Form_pg_type) GETSTRUCT(likeType); internalLength = likeForm->typlen; byValue = likeForm->typbyval; alignment = likeForm->typalign; storage = likeForm->typstorage; ReleaseSysCache(likeType); } if (internalLengthEl) internalLength = defGetTypeLength(internalLengthEl); if (inputNameEl) inputName = defGetQualifiedName(inputNameEl); if (outputNameEl) outputName = defGetQualifiedName(outputNameEl); if (receiveNameEl) receiveName = defGetQualifiedName(receiveNameEl); if (sendNameEl) sendName = defGetQualifiedName(sendNameEl); if (typmodinNameEl) typmodinName = defGetQualifiedName(typmodinNameEl); if (typmodoutNameEl) typmodoutName = defGetQualifiedName(typmodoutNameEl); if (analyzeNameEl) analyzeName = defGetQualifiedName(analyzeNameEl); if (categoryEl) { char *p = defGetString(categoryEl); category = p[0]; /* restrict to non-control ASCII */ if (category < 32 || category > 126) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid type category \"%s\": must be simple ASCII", p))); } if (preferredEl) preferred = defGetBoolean(preferredEl); if (delimiterEl) { char *p = defGetString(delimiterEl); delimiter = p[0]; /* XXX shouldn't we restrict the delimiter? */ } if (elemTypeEl) { elemType = typenameTypeId(NULL, defGetTypeName(elemTypeEl)); /* disallow arrays of pseudotypes */ if (get_typtype(elemType) == TYPTYPE_PSEUDO) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("array element type cannot be %s", format_type_be(elemType)))); } if (defaultValueEl) defaultValue = defGetString(defaultValueEl); if (byValueEl) byValue = defGetBoolean(byValueEl); if (alignmentEl) { char *a = defGetString(alignmentEl); /* * Note: if argument was an unquoted identifier, parser will have * applied translations to it, so be prepared to recognize translated * type names as well as the nominal form. */ if (pg_strcasecmp(a, "double") == 0 || pg_strcasecmp(a, "float8") == 0 || pg_strcasecmp(a, "pg_catalog.float8") == 0) alignment = 'd'; else if (pg_strcasecmp(a, "int4") == 0 || pg_strcasecmp(a, "pg_catalog.int4") == 0) alignment = 'i'; else if (pg_strcasecmp(a, "int2") == 0 || pg_strcasecmp(a, "pg_catalog.int2") == 0) alignment = 's'; else if (pg_strcasecmp(a, "char") == 0 || pg_strcasecmp(a, "pg_catalog.bpchar") == 0) alignment = 'c'; else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("alignment \"%s\" not recognized", a))); } if (storageEl) { char *a = defGetString(storageEl); if (pg_strcasecmp(a, "plain") == 0) storage = 'p'; else if (pg_strcasecmp(a, "external") == 0) storage = 'e'; else if (pg_strcasecmp(a, "extended") == 0) storage = 'x'; else if (pg_strcasecmp(a, "main") == 0) storage = 'm'; else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("storage \"%s\" not recognized", a))); } if (collatableEl) collation = defGetBoolean(collatableEl) ? DEFAULT_COLLATION_OID : InvalidOid; /* * make sure we have our required definitions */ if (inputName == NIL) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("type input function must be specified"))); if (outputName == NIL) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("type output function must be specified"))); if (typmodinName == NIL && typmodoutName != NIL) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("type modifier output function is useless without a type modifier input function"))); /* * Convert I/O proc names to OIDs */ inputOid = findTypeInputFunction(inputName, typoid); outputOid = findTypeOutputFunction(outputName, typoid); if (receiveName) receiveOid = findTypeReceiveFunction(receiveName, typoid); if (sendName) sendOid = findTypeSendFunction(sendName, typoid); /* * Verify that I/O procs return the expected thing. If we see OPAQUE, * complain and change it to the correct type-safe choice. */ resulttype = get_func_rettype(inputOid); if (resulttype != typoid) { if (resulttype == OPAQUEOID) { /* backwards-compatibility hack */ ereport(WARNING, (errmsg("changing return type of function %s from \"opaque\" to %s", NameListToString(inputName), typeName))); SetFunctionReturnType(inputOid, typoid); } else ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("type input function %s must return type %s", NameListToString(inputName), typeName))); } resulttype = get_func_rettype(outputOid); if (resulttype != CSTRINGOID) { if (resulttype == OPAQUEOID) { /* backwards-compatibility hack */ ereport(WARNING, (errmsg("changing return type of function %s from \"opaque\" to \"cstring\"", NameListToString(outputName)))); SetFunctionReturnType(outputOid, CSTRINGOID); } else ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("type output function %s must return type \"cstring\"", NameListToString(outputName)))); } if (receiveOid) { resulttype = get_func_rettype(receiveOid); if (resulttype != typoid) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("type receive function %s must return type %s", NameListToString(receiveName), typeName))); } if (sendOid) { resulttype = get_func_rettype(sendOid); if (resulttype != BYTEAOID) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("type send function %s must return type \"bytea\"", NameListToString(sendName)))); } /* * Convert typmodin/out function proc names to OIDs. */ if (typmodinName) typmodinOid = findTypeTypmodinFunction(typmodinName); if (typmodoutName) typmodoutOid = findTypeTypmodoutFunction(typmodoutName); /* * Convert analysis function proc name to an OID. If no analysis function * is specified, we'll use zero to select the built-in default algorithm. */ if (analyzeName) analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid); /* * Check permissions on functions. We choose to require the creator/owner * of a type to also own the underlying functions. Since creating a type * is tantamount to granting public execute access on the functions, the * minimum sane check would be for execute-with-grant-option. But we * don't have a way to make the type go away if the grant option is * revoked, so ownership seems better. */ #ifdef NOT_USED /* XXX this is unnecessary given the superuser check above */ if (inputOid && !pg_proc_ownercheck(inputOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(inputName)); if (outputOid && !pg_proc_ownercheck(outputOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(outputName)); if (receiveOid && !pg_proc_ownercheck(receiveOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(receiveName)); if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(sendName)); if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(typmodinName)); if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(typmodoutName)); if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(analyzeName)); #endif array_oid = AssignTypeArrayOid(); /* * now have TypeCreate do all the real work. * * Note: the pg_type.oid is stored in user tables as array elements (base * types) in ArrayType and in composite types in DatumTupleFields. This * oid must be preserved by binary upgrades. */ typoid = TypeCreate(InvalidOid, /* no predetermined type OID */ typeName, /* type name */ typeNamespace, /* namespace */ InvalidOid, /* relation oid (n/a here) */ 0, /* relation kind (ditto) */ GetUserId(), /* owner's ID */ internalLength, /* internal size */ TYPTYPE_BASE, /* type-type (base type) */ category, /* type-category */ preferred, /* is it a preferred type? */ delimiter, /* array element delimiter */ inputOid, /* input procedure */ outputOid, /* output procedure */ receiveOid, /* receive procedure */ sendOid, /* send procedure */ typmodinOid, /* typmodin procedure */ typmodoutOid, /* typmodout procedure */ analyzeOid, /* analyze procedure */ elemType, /* element type ID */ false, /* this is not an array type */ array_oid, /* array type we are about to create */ InvalidOid, /* base type ID (only for domains) */ defaultValue, /* default type value */ NULL, /* no binary form available */ byValue, /* passed by value */ alignment, /* required alignment */ storage, /* TOAST strategy */ -1, /* typMod (Domains only) */ 0, /* Array Dimensions of typbasetype */ false, /* Type NOT NULL */ collation); /* type's collation */ /* * Create the array type that goes with it. */ array_type = makeArrayTypeName(typeName, typeNamespace); /* alignment must be 'i' or 'd' for arrays */ alignment = (alignment == 'd') ? 'd' : 'i'; typoid = TypeCreate(array_oid, /* force assignment of this type OID */ array_type, /* type name */ typeNamespace, /* namespace */ InvalidOid, /* relation oid (n/a here) */ 0, /* relation kind (ditto) */ GetUserId(), /* owner's ID */ -1, /* internal size (always varlena) */ TYPTYPE_BASE, /* type-type (base type) */ TYPCATEGORY_ARRAY, /* type-category (array) */ false, /* array types are never preferred */ delimiter, /* array element delimiter */ F_ARRAY_IN, /* input procedure */ F_ARRAY_OUT, /* output procedure */ F_ARRAY_RECV, /* receive procedure */ F_ARRAY_SEND, /* send procedure */ typmodinOid, /* typmodin procedure */ typmodoutOid, /* typmodout procedure */ F_ARRAY_TYPANALYZE, /* analyze procedure */ typoid, /* element type ID */ true, /* yes this is an array type */ InvalidOid, /* no further array type */ InvalidOid, /* base type ID */ NULL, /* never a default type value */ NULL, /* binary default isn't sent either */ false, /* never passed by value */ alignment, /* see above */ 'x', /* ARRAY is always toastable */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ false, /* Type NOT NULL */ collation); /* type's collation */ pfree(array_type); return typoid; }
Definition at line 3030 of file typecmds.c.
References AccessShareLock, Anum_pg_constraint_conbin, Anum_pg_constraint_contypid, BTEqualStrategyNumber, DomainConstraintState::check_expr, CONSTRAINT_CHECK, ConstraintRelationId, DomainConstraintState::constrainttype, ConstraintTypidIndexId, elog, ERROR, ExecInitExpr(), expression_planner(), fastgetattr, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, lcons(), makeNode, DomainConstraintState::name, NameStr, NULL, ObjectIdGetDatum, pstrdup(), RelationData::rd_att, ReleaseSysCache(), ScanKeyInit(), SearchSysCache1, SnapshotNow, stringToNode(), systable_beginscan(), systable_endscan(), systable_getnext(), TextDatumGetCString, TYPEOID, TYPTYPE_DOMAIN, and val.
Referenced by ATColumnChangeRequiresRewrite(), ATExecAddColumn(), domain_state_setup(), and ExecInitExpr().
{ List *result = NIL; bool notNull = false; Relation conRel; conRel = heap_open(ConstraintRelationId, AccessShareLock); for (;;) { HeapTuple tup; HeapTuple conTup; Form_pg_type typTup; ScanKeyData key[1]; SysScanDesc scan; tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", typeOid); typTup = (Form_pg_type) GETSTRUCT(tup); if (typTup->typtype != TYPTYPE_DOMAIN) { /* Not a domain, so done */ ReleaseSysCache(tup); break; } /* Test for NOT NULL Constraint */ if (typTup->typnotnull) notNull = true; /* Look for CHECK Constraints on this domain */ ScanKeyInit(&key[0], Anum_pg_constraint_contypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(typeOid)); scan = systable_beginscan(conRel, ConstraintTypidIndexId, true, SnapshotNow, 1, key); while (HeapTupleIsValid(conTup = systable_getnext(scan))) { Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup); Datum val; bool isNull; Expr *check_expr; DomainConstraintState *r; /* Ignore non-CHECK constraints (presently, shouldn't be any) */ if (c->contype != CONSTRAINT_CHECK) continue; /* * Not expecting conbin to be NULL, but we'll test for it anyway */ val = fastgetattr(conTup, Anum_pg_constraint_conbin, conRel->rd_att, &isNull); if (isNull) elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin", NameStr(typTup->typname), NameStr(c->conname)); check_expr = (Expr *) stringToNode(TextDatumGetCString(val)); /* ExecInitExpr assumes we've planned the expression */ check_expr = expression_planner(check_expr); r = makeNode(DomainConstraintState); r->constrainttype = DOM_CONSTRAINT_CHECK; r->name = pstrdup(NameStr(c->conname)); r->check_expr = ExecInitExpr(check_expr, NULL); /* * use lcons() here because constraints of lower domains should be * applied earlier. */ result = lcons(r, result); } systable_endscan(scan); /* loop to next domain in stack */ typeOid = typTup->typbasetype; ReleaseSysCache(tup); } heap_close(conRel, AccessShareLock); /* * Only need to add one NOT NULL check regardless of how many domains in * the stack request it. */ if (notNull) { DomainConstraintState *r = makeNode(DomainConstraintState); r->constrainttype = DOM_CONSTRAINT_NOTNULL; r->name = pstrdup("NOT NULL"); r->check_expr = NULL; /* lcons to apply the nullness check FIRST */ result = lcons(r, result); } return result; }
void RemoveTypeById | ( | Oid | typeOid | ) |
Definition at line 638 of file typecmds.c.
References elog, EnumValuesDelete(), ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, RangeDelete(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), HeapTupleData::t_self, TYPEOID, TypeRelationId, TYPTYPE_ENUM, and TYPTYPE_RANGE.
Referenced by doDeletion().
{ Relation relation; HeapTuple tup; relation = heap_open(TypeRelationId, RowExclusiveLock); tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", typeOid); simple_heap_delete(relation, &tup->t_self); /* * If it is an enum, delete the pg_enum entries too; we don't bother with * making dependency entries for those, so it has to be done "by hand" * here. */ if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM) EnumValuesDelete(typeOid); /* * If it is a range type, delete the pg_range entry too; we don't bother * with making a dependency entry for that, so it has to be done "by hand" * here. */ if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE) RangeDelete(typeOid); ReleaseSysCache(tup); heap_close(relation, RowExclusiveLock); }
Oid RenameType | ( | RenameStmt * | stmt | ) |
Definition at line 3142 of file typecmds.c.
References aclcheck_error_type(), ACLCHECK_NOT_OWNER, elog, ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), get_array_type(), get_rel_relkind(), GETSTRUCT, GetUserId(), heap_close, heap_open(), HeapTupleIsValid, makeTypeNameFromNameList(), RenameStmt::newname, NULL, RenameStmt::object, OBJECT_DOMAIN, ObjectIdGetDatum, OidIsValid, pg_type_ownercheck(), RELKIND_COMPOSITE_TYPE, RenameRelationInternal(), RenameStmt::renameType, RenameTypeInternal(), RowExclusiveLock, SearchSysCacheCopy1, typenameTypeId(), TYPEOID, TypeRelationId, TYPTYPE_COMPOSITE, and TYPTYPE_DOMAIN.
Referenced by ExecRenameStmt().
{ List *names = stmt->object; const char *newTypeName = stmt->newname; TypeName *typename; Oid typeOid; Relation rel; HeapTuple tup; Form_pg_type typTup; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeTypeNameFromNameList(names); typeOid = typenameTypeId(NULL, typename); /* Look up the type in the type table */ rel = heap_open(TypeRelationId, RowExclusiveLock); tup = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", typeOid); typTup = (Form_pg_type) GETSTRUCT(tup); /* check permissions on type */ if (!pg_type_ownercheck(typeOid, GetUserId())) aclcheck_error_type(ACLCHECK_NOT_OWNER, typeOid); /* ALTER DOMAIN used on a non-domain? */ if (stmt->renameType == OBJECT_DOMAIN && typTup->typtype != TYPTYPE_DOMAIN) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a domain", format_type_be(typeOid)))); /* * If it's a composite type, we need to check that it really is a * free-standing composite type, and not a table's rowtype. We want people * to use ALTER TABLE not ALTER TYPE for that case. */ if (typTup->typtype == TYPTYPE_COMPOSITE && get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("%s is a table's row type", format_type_be(typeOid)), errhint("Use ALTER TABLE instead."))); /* don't allow direct alteration of array types, either */ if (OidIsValid(typTup->typelem) && get_array_type(typTup->typelem) == typeOid) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot alter array type %s", format_type_be(typeOid)), errhint("You can alter type %s, which will alter the array type as well.", format_type_be(typTup->typelem)))); /* * If type is composite we need to rename associated pg_class entry too. * RenameRelationInternal will call RenameTypeInternal automatically. */ if (typTup->typtype == TYPTYPE_COMPOSITE) RenameRelationInternal(typTup->typrelid, newTypeName, false); else RenameTypeInternal(typeOid, newTypeName, typTup->typnamespace); /* Clean up */ heap_close(rel, RowExclusiveLock); return typeOid; }