📄 typecmds.c
字号:
* Since VARNOs aren't allowed in domain constraints, relation context * isn't required as anything other than a shell. */ ccsrc = deparse_expression(expr, deparse_context_for(domainName, InvalidOid), false, false); /* * Store the constraint in pg_constraint */ CreateConstraintEntry(constr->name, /* Constraint Name */ domainNamespace, /* namespace */ CONSTRAINT_CHECK, /* Constraint Type */ false, /* Is Deferrable */ false, /* Is Deferred */ InvalidOid, /* not a relation constraint */ NULL, 0, domainOid, /* domain constraint */ InvalidOid, /* Foreign key fields */ NULL, 0, ' ', ' ', ' ', InvalidOid, expr, /* Tree form check constraint */ ccbin, /* Binary form check constraint */ ccsrc); /* Source form check constraint */ /* * Return the compiled constraint expression so the calling routine can * perform any additional required tests. */ return ccbin;}/* * GetDomainConstraints - get a list of the current constraints of domain * * Returns a possibly-empty list of DomainConstraintState nodes. * * This is called by the executor during plan startup for a CoerceToDomain * expression node. The given constraints will be checked for each value * passed through the node. * * We allow this to be called for non-domain types, in which case the result * is always NIL. */List *GetDomainConstraints(Oid typeOid){ 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 = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeOid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", typeOid); typTup = (Form_pg_type) GETSTRUCT(tup); if (typTup->typtype != 'd') { /* 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(DatumGetCString(DirectFunctionCall1(textout, val))); /* ExecInitExpr assumes we already fixed opfuncids */ fix_opfuncids((Node *) 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;}/* * Change the owner of a type. */voidAlterTypeOwner(List *names, Oid newOwnerId){ TypeName *typename; Oid typeOid; Relation rel; HeapTuple tup; Form_pg_type typTup; AclResult aclresult; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeNode(TypeName); typename->names = names; typename->typmod = -1; typename->arrayBounds = NIL; /* Lock the type table */ rel = heap_open(TypeRelationId, RowExclusiveLock); /* Use LookupTypeName here so that shell types can be processed (why?) */ typeOid = LookupTypeName(typename); if (!OidIsValid(typeOid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(typename)))); tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(typeOid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", typeOid); typTup = (Form_pg_type) GETSTRUCT(tup); /* * If it's a composite type, we need to check that it really is a * free-standing composite type, and not a table's underlying type. We * want people to use ALTER TABLE not ALTER TYPE for that case. */ if (typTup->typtype == 'c' && get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is a table's row type", TypeNameToString(typename)))); /* * 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(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, TypeNameToString(typename)); /* 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)); } /* * 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 */ changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId); } /* Clean up */ heap_close(rel, RowExclusiveLock);}/* * AlterTypeOwnerInternal - change type owner unconditionally * * This is currently only used to propagate ALTER TABLE OWNER to the * table's rowtype. It assumes the caller has done all needed checks. */voidAlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId){ Relation rel; HeapTuple tup; Form_pg_type typTup; rel = heap_open(TypeRelationId, RowExclusiveLock); tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(typeOid), 0, 0, 0); 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 */ changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId); /* Clean up */ heap_close(rel, RowExclusiveLock);}/* * Execute ALTER TYPE SET SCHEMA */voidAlterTypeNamespace(List *names, const char *newschema){ TypeName *typename; Oid typeOid; Oid nspOid; /* get type OID */ typename = makeNode(TypeName); typename->names = names; typename->typmod = -1; typename->arrayBounds = NIL; typeOid = LookupTypeName(typename); if (!OidIsValid(typeOid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(typename)))); /* check permissions on type */ if (!pg_type_ownercheck(typeOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, format_type_be(typeOid)); /* get schema OID and check its permissions */ nspOid = LookupCreationNamespace(newschema); /* and do the work */ AlterTypeNamespaceInternal(typeOid, nspOid, true);}/* * Move specified type to new namespace. * * Caller must have already checked privileges. * * If errorOnTableType is TRUE, the function errors out if the type is * a table type. ALTER TABLE has to be used to move a table to a new * namespace. */voidAlterTypeNamespaceInternal(Oid typeOid, Oid nspOid, bool errorOnTableType){ Relation rel; HeapTuple tup; Form_pg_type typform; Oid oldNspOid; bool isCompositeType; rel = heap_open(TypeRelationId, RowExclusiveLock); tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(typeOid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", typeOid); typform = (Form_pg_type) GETSTRUCT(tup); oldNspOid = typform->typnamespace; if (oldNspOid == nspOid) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type %s is already in schema \"%s\"", format_type_be(typeOid), get_namespace_name(nspOid)))); /* disallow renaming into or out of temp schemas */ if (isAnyTempNamespace(nspOid) || isAnyTempNamespace(oldNspOid)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot move objects into or out of temporary schemas"))); /* same for TOAST schema */ if (nspOid == PG_TOAST_NAMESPACE || oldNspOid == PG_TOAST_NAMESPACE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot move objects into or out of TOAST schema"))); /* check for duplicate name (more friendly than unique-index failure) */ if (SearchSysCacheExists(TYPENAMENSP, CStringGetDatum(NameStr(typform->typname)), ObjectIdGetDatum(nspOid), 0, 0)) 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 == 'c' && get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE); /* Enforce not-table-type if requested */ if (typform->typtype == 'c' && !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 SET SCHEMA 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); /* * The dependency on the schema is listed under the pg_class entry, so * tell AlterRelationNamespaceInternal to fix it. */ AlterRelationNamespaceInternal(classRel, typform->typrelid, oldNspOid, nspOid, true); 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); } else { /* If it's a domain, it might have constraints */ if (typform->typtype == 'd') AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true); /* * Update dependency on schema, if any --- a table rowtype has not got * one. */ if (typform->typtype != 'c') if (changeDependencyFor(TypeRelationId, typeOid, NamespaceRelationId, oldNspOid, nspOid) != 1) elog(ERROR, "failed to change schema dependency for type %s", format_type_be(typeOid)); } heap_freetuple(tup); heap_close(rel, RowExclusiveLock);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -