tablecmds.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,338 行 · 第 1/5 页

C
2,338
字号
 *			the column will not have a default. *		(3) If conflicting defaults are inherited from different parents *			(and not overridden by the child), an error is raised. *		(4) Otherwise the inherited default is used. *		Rule (3) is new in Postgres 7.1; in earlier releases you got a *		rather arbitrary choice of which parent default to use. *---------- */static List *MergeAttributes(List *schema, List *supers, bool istemp,				List **supOids, List **supconstr, bool *supHasOids){	List	   *entry;	List	   *inhSchema = NIL;	List	   *parentOids = NIL;	List	   *constraints = NIL;	bool		parentHasOids = false;	bool		have_bogus_defaults = false;	char	   *bogus_marker = "Bogus!";		/* marks conflicting												 * defaults */	int			child_attno;	/*	 * Check for duplicate names in the explicit list of attributes.	 *	 * Although we might consider merging such entries in the same way that	 * we handle name conflicts for inherited attributes, it seems to make	 * more sense to assume such conflicts are errors.	 */	foreach(entry, schema)	{		ColumnDef  *coldef = lfirst(entry);		List	   *rest;		foreach(rest, lnext(entry))		{			ColumnDef  *restdef = lfirst(rest);			if (strcmp(coldef->colname, restdef->colname) == 0)				ereport(ERROR,						(errcode(ERRCODE_DUPLICATE_COLUMN),						 errmsg("column \"%s\" duplicated",								coldef->colname)));		}	}	/*	 * Scan the parents left-to-right, and merge their attributes to form	 * a list of inherited attributes (inhSchema).	Also check to see if	 * we need to inherit an OID column.	 */	child_attno = 0;	foreach(entry, supers)	{		RangeVar   *parent = (RangeVar *) lfirst(entry);		Relation	relation;		TupleDesc	tupleDesc;		TupleConstr *constr;		AttrNumber *newattno;		AttrNumber	parent_attno;		relation = heap_openrv(parent, AccessShareLock);		if (relation->rd_rel->relkind != RELKIND_RELATION)			ereport(ERROR,					(errcode(ERRCODE_WRONG_OBJECT_TYPE),					 errmsg("inherited relation \"%s\" is not a table",							parent->relname)));		/* Permanent rels cannot inherit from temporary ones */		if (!istemp && isTempNamespace(RelationGetNamespace(relation)))			ereport(ERROR,					(errcode(ERRCODE_WRONG_OBJECT_TYPE),				  errmsg("cannot inherit from temporary relation \"%s\"",						 parent->relname)));		/*		 * We should have an UNDER permission flag for this, but for now,		 * demand that creator of a child table own the parent.		 */		if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,						   RelationGetRelationName(relation));		/*		 * Reject duplications in the list of parents.		 */		if (oidMember(RelationGetRelid(relation), parentOids))			ereport(ERROR,					(errcode(ERRCODE_DUPLICATE_TABLE),					 errmsg("inherited relation \"%s\" duplicated",							parent->relname)));		parentOids = lappendo(parentOids, RelationGetRelid(relation));		parentHasOids |= relation->rd_rel->relhasoids;		tupleDesc = RelationGetDescr(relation);		constr = tupleDesc->constr;		/*		 * newattno[] will contain the child-table attribute numbers for		 * the attributes of this parent table.  (They are not the same		 * for parents after the first one, nor if we have dropped		 * columns.)  +1 is to prevent error if parent has zero columns.		 */		newattno = (AttrNumber *)			palloc((tupleDesc->natts + 1) * sizeof(AttrNumber));		for (parent_attno = 1; parent_attno <= tupleDesc->natts;			 parent_attno++)		{			Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];			char	   *attributeName = NameStr(attribute->attname);			int			exist_attno;			ColumnDef  *def;			TypeName   *typename;			/*			 * Ignore dropped columns in the parent.			 */			if (attribute->attisdropped)			{				/*				 * change_varattnos_of_a_node asserts that this is greater				 * than zero, so if anything tries to use it, we should				 * find out.				 */				newattno[parent_attno - 1] = 0;				continue;			}			/*			 * Does it conflict with some previously inherited column?			 */			exist_attno = findAttrByName(attributeName, inhSchema);			if (exist_attno > 0)			{				/*				 * Yes, try to merge the two column definitions. They must				 * have the same type and typmod.				 */				ereport(NOTICE,						(errmsg("merging multiple inherited definitions of column \"%s\"",								attributeName)));				def = (ColumnDef *) nth(exist_attno - 1, inhSchema);				if (typenameTypeId(def->typename) != attribute->atttypid ||					def->typename->typmod != attribute->atttypmod)					ereport(ERROR,							(errcode(ERRCODE_DATATYPE_MISMATCH),							 errmsg("inherited column \"%s\" has a type conflict",									attributeName),							 errdetail("%s versus %s",									   TypeNameToString(def->typename),								  format_type_be(attribute->atttypid))));				def->inhcount++;				/* Merge of NOT NULL constraints = OR 'em together */				def->is_not_null |= attribute->attnotnull;				/* Default and other constraints are handled below */				newattno[parent_attno - 1] = exist_attno;			}			else			{				/*				 * No, create a new inherited column				 */				def = makeNode(ColumnDef);				def->colname = pstrdup(attributeName);				typename = makeNode(TypeName);				typename->typeid = attribute->atttypid;				typename->typmod = attribute->atttypmod;				def->typename = typename;				def->inhcount = 1;				def->is_local = false;				def->is_not_null = attribute->attnotnull;				def->raw_default = NULL;				def->cooked_default = NULL;				def->constraints = NIL;				def->support = NULL;				inhSchema = lappend(inhSchema, def);				newattno[parent_attno - 1] = ++child_attno;			}			/*			 * Copy default if any			 */			if (attribute->atthasdef)			{				char	   *this_default = NULL;				AttrDefault *attrdef;				int			i;				/* Find default in constraint structure */				Assert(constr != NULL);				attrdef = constr->defval;				for (i = 0; i < constr->num_defval; i++)				{					if (attrdef[i].adnum == parent_attno)					{						this_default = attrdef[i].adbin;						break;					}				}				Assert(this_default != NULL);				/*				 * If default expr could contain any vars, we'd need to				 * fix 'em, but it can't; so default is ready to apply to				 * child.				 *				 * If we already had a default from some prior parent, check				 * to see if they are the same.  If so, no problem; if				 * not, mark the column as having a bogus default. Below,				 * we will complain if the bogus default isn't overridden				 * by the child schema.				 */				Assert(def->raw_default == NULL);				if (def->cooked_default == NULL)					def->cooked_default = pstrdup(this_default);				else if (strcmp(def->cooked_default, this_default) != 0)				{					def->cooked_default = bogus_marker;					have_bogus_defaults = true;				}			}		}		/*		 * Now copy the constraints of this parent, adjusting attnos using		 * the completed newattno[] map		 */		if (constr && constr->num_check > 0)		{			ConstrCheck *check = constr->check;			int			i;			for (i = 0; i < constr->num_check; i++)			{				Constraint *cdef = makeNode(Constraint);				Node	   *expr;				cdef->contype = CONSTR_CHECK;				/*				 * Do not inherit generated constraint names, since they				 * might conflict across multiple inheritance parents.				 * (But conflicts between user-assigned names will cause				 * an error.)				 */				if (ConstraintNameIsGenerated(check[i].ccname))					cdef->name = NULL;				else					cdef->name = pstrdup(check[i].ccname);				cdef->raw_expr = NULL;				/* adjust varattnos of ccbin here */				expr = stringToNode(check[i].ccbin);				change_varattnos_of_a_node(expr, newattno);				cdef->cooked_expr = nodeToString(expr);				constraints = lappend(constraints, cdef);			}		}		pfree(newattno);		/*		 * Close the parent rel, but keep our AccessShareLock on it until		 * xact commit.  That will prevent someone else from deleting or		 * ALTERing the parent before the child is committed.		 */		heap_close(relation, NoLock);	}	/*	 * If we had no inherited attributes, the result schema is just the	 * explicitly declared columns.  Otherwise, we need to merge the	 * declared columns into the inherited schema list.	 */	if (inhSchema != NIL)	{		foreach(entry, schema)		{			ColumnDef  *newdef = lfirst(entry);			char	   *attributeName = newdef->colname;			int			exist_attno;			/*			 * Does it conflict with some previously inherited column?			 */			exist_attno = findAttrByName(attributeName, inhSchema);			if (exist_attno > 0)			{				ColumnDef  *def;				/*				 * Yes, try to merge the two column definitions. They must				 * have the same type and typmod.				 */				ereport(NOTICE,						(errmsg("merging column \"%s\" with inherited definition",								attributeName)));				def = (ColumnDef *) nth(exist_attno - 1, inhSchema);				if (typenameTypeId(def->typename) != typenameTypeId(newdef->typename) ||					def->typename->typmod != newdef->typename->typmod)					ereport(ERROR,							(errcode(ERRCODE_DATATYPE_MISMATCH),						   errmsg("column \"%s\" has a type conflict",								  attributeName),							 errdetail("%s versus %s",									   TypeNameToString(def->typename),								   TypeNameToString(newdef->typename))));				/* Mark the column as locally defined */				def->is_local = true;				/* Merge of NOT NULL constraints = OR 'em together */				def->is_not_null |= newdef->is_not_null;				/* If new def has a default, override previous default */				if (newdef->raw_default != NULL)				{					def->raw_default = newdef->raw_default;					def->cooked_default = newdef->cooked_default;				}			}			else			{				/*				 * No, attach new column to result schema				 */				inhSchema = lappend(inhSchema, newdef);			}		}		schema = inhSchema;	}	/*	 * If we found any conflicting parent default values, check to make	 * sure they were overridden by the child.	 */	if (have_bogus_defaults)	{		foreach(entry, schema)		{			ColumnDef  *def = lfirst(entry);			if (def->cooked_default == bogus_marker)				ereport(ERROR,						(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),						 errmsg("column \"%s\" inherits conflicting default values",								def->colname),						 errhint("To resolve the conflict, specify a default explicitly.")));		}	}	*supOids = parentOids;	*supconstr = constraints;	*supHasOids = parentHasOids;	return schema;}/* * complementary static functions for MergeAttributes(). * * Varattnos of pg_constraint.conbin must be rewritten when subclasses inherit * constraints from parent classes, since the inherited attributes could * be given different column numbers in multiple-inheritance cases. * * Note that the passed node tree is modified in place! */static boolchange_varattnos_walker(Node *node, const AttrNumber *newattno){	if (node == NULL)		return false;	if (IsA(node, Var))	{		Var		   *var = (Var *) node;		if (var->varlevelsup == 0 && var->varno == 1 &&			var->varattno > 0)		{			/*			 * ??? the following may be a problem when the node is			 * multiply referenced though stringToNode() doesn't create			 * such a node currently.			 */			Assert(newattno[var->varattno - 1] > 0);			var->varattno = newattno[var->varattno - 1];		}		return false;	}	return expression_tree_walker(node, change_varattnos_walker,								  (void *) newattno);}static boolchange_varattnos_of_a_node(Node *node, const AttrNumber *newattno){	return change_varattnos_walker(node, newattno);}/* * StoreCatalogInheritance *		Updates the system catalogs with proper inheritance information. * * supers is a list of the OIDs of the new relation's direct ancestors. */static voidStoreCatalogInheritance(Oid relationId, List *supers){	Relation	relation;	TupleDesc	desc;	int16		seqNumber;	List	   *entry;	HeapTuple	tuple;	/*	 * sanity checks	 */	AssertArg(OidIsValid(relationId));	if (supers == NIL)		return;	/*	 * Store INHERITS information in pg_inherits using direct ancestors	 * only. Also enter dependencies on the direct ancestors, and make sure	 * they are marked with relhassubclass = true.	 *	 * (Once upon a time, both direct and indirect ancestors were found here	 * and then entered into pg_ipl.  Since that catalog doesn't exist anymore,	 * there's no need to look for indirect ancestors.)	 */	relation = heap_openr(InheritsRelationName, RowExclusiveLock);	desc = RelationGetDescr(relation);	seqNumber = 1;	foreach(entry, supers)	{		Oid			parentOid = lfirsto(entry);		Datum		datum[Natts_pg_inherits];		char		nullarr[Natts_pg_inherits];		ObjectAddress childobject,					parentobject;		datum[0] = ObjectIdGetDatum(relationId);		/* inhrel */		datum[1] = ObjectIdGetDatum(parentOid);	/* inhparent */		datum[2] = Int16GetDatum(seqNumber);	/* inhseqno */		nullarr[0] = ' ';		nullarr[1] = ' ';		nullarr[2] = ' ';		tuple = heap_formtuple(desc, datum, nullarr);		simple_heap_insert(relation, tuple);		CatalogUpdateIndexes(relation, tuple);		heap_freetuple(tuple);		/*		 * Store a dependency too		 */		parentobject.classId = RelOid_pg_class;		parentobject.objectId = parentOid;		parentobject.objectSubId = 0;		childobject.classId = RelOid_pg_class;		childobject.objectId = relationId;		childobject.objectSubId = 0;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?