analyze.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,222 行 · 第 1/5 页

C
2,222
字号
		 */		seqstmt = makeNode(CreateSeqStmt);		seqstmt->sequence = makeRangeVar(snamespace, sname);		seqstmt->options = NIL;		cxt->blist = lappend(cxt->blist, seqstmt);		/*		 * Mark the ColumnDef so that during execution, an appropriate		 * dependency will be added from the sequence to the column.		 */		column->support = makeRangeVar(snamespace, sname);		/*		 * Create appropriate constraints for SERIAL.  We do this in full,		 * rather than shortcutting, so that we will detect any conflicting		 * constraints the user wrote (like a different DEFAULT).		 *		 * Create an expression tree representing the function call		 * nextval('sequencename').  We cannot reduce the raw tree to cooked		 * form until after the sequence is created, but there's no need to do		 * so.		 */		qstring = quote_qualified_identifier(snamespace, sname);		snamenode = makeNode(A_Const);		snamenode->val.type = T_String;		snamenode->val.val.str = qstring;		snamenode->typename = SystemTypeName("regclass");		funccallnode = makeNode(FuncCall);		funccallnode->funcname = SystemFuncName("nextval");		funccallnode->args = list_make1(snamenode);		funccallnode->agg_star = false;		funccallnode->agg_distinct = false;		constraint = makeNode(Constraint);		constraint->contype = CONSTR_DEFAULT;		constraint->raw_expr = (Node *) funccallnode;		constraint->cooked_expr = NULL;		constraint->keys = NIL;		column->constraints = lappend(column->constraints, constraint);		constraint = makeNode(Constraint);		constraint->contype = CONSTR_NOTNULL;		column->constraints = lappend(column->constraints, constraint);	}	/* Process column constraints, if any... */	transformConstraintAttrs(column->constraints);	saw_nullable = false;	foreach(clist, column->constraints)	{		constraint = lfirst(clist);		/*		 * If this column constraint is a FOREIGN KEY constraint, then we fill		 * in the current attribute's name and throw it into the list of FK		 * constraints to be processed later.		 */		if (IsA(constraint, FkConstraint))		{			FkConstraint *fkconstraint = (FkConstraint *) constraint;			fkconstraint->fk_attrs = list_make1(makeString(column->colname));			cxt->fkconstraints = lappend(cxt->fkconstraints, fkconstraint);			continue;		}		Assert(IsA(constraint, Constraint));		switch (constraint->contype)		{			case CONSTR_NULL:				if (saw_nullable && column->is_not_null)					ereport(ERROR,							(errcode(ERRCODE_SYNTAX_ERROR),							 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",								  column->colname, cxt->relation->relname)));				column->is_not_null = FALSE;				saw_nullable = true;				break;			case CONSTR_NOTNULL:				if (saw_nullable && !column->is_not_null)					ereport(ERROR,							(errcode(ERRCODE_SYNTAX_ERROR),							 errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",								  column->colname, cxt->relation->relname)));				column->is_not_null = TRUE;				saw_nullable = true;				break;			case CONSTR_DEFAULT:				if (column->raw_default != NULL)					ereport(ERROR,							(errcode(ERRCODE_SYNTAX_ERROR),							 errmsg("multiple default values specified for column \"%s\" of table \"%s\"",								  column->colname, cxt->relation->relname)));				column->raw_default = constraint->raw_expr;				Assert(constraint->cooked_expr == NULL);				break;			case CONSTR_PRIMARY:			case CONSTR_UNIQUE:				if (constraint->keys == NIL)					constraint->keys = list_make1(makeString(column->colname));				cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);				break;			case CONSTR_CHECK:				cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);				break;			case CONSTR_ATTR_DEFERRABLE:			case CONSTR_ATTR_NOT_DEFERRABLE:			case CONSTR_ATTR_DEFERRED:			case CONSTR_ATTR_IMMEDIATE:				/* transformConstraintAttrs took care of these */				break;			default:				elog(ERROR, "unrecognized constraint type: %d",					 constraint->contype);				break;		}	}}static voidtransformTableConstraint(ParseState *pstate, CreateStmtContext *cxt,						 Constraint *constraint){	switch (constraint->contype)	{		case CONSTR_PRIMARY:		case CONSTR_UNIQUE:			cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);			break;		case CONSTR_CHECK:			cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);			break;		case CONSTR_NULL:		case CONSTR_NOTNULL:		case CONSTR_DEFAULT:		case CONSTR_ATTR_DEFERRABLE:		case CONSTR_ATTR_NOT_DEFERRABLE:		case CONSTR_ATTR_DEFERRED:		case CONSTR_ATTR_IMMEDIATE:			elog(ERROR, "invalid context for constraint type %d",				 constraint->contype);			break;		default:			elog(ERROR, "unrecognized constraint type: %d",				 constraint->contype);			break;	}}/* * transformInhRelation * * Change the LIKE <subtable> portion of a CREATE TABLE statement into the * column definitions which recreate the user defined column portions of <subtable>. */static voidtransformInhRelation(ParseState *pstate, CreateStmtContext *cxt,					 InhRelation *inhRelation){	AttrNumber	parent_attno;	Relation	relation;	TupleDesc	tupleDesc;	TupleConstr *constr;	AclResult	aclresult;	relation = heap_openrv(inhRelation->relation, AccessShareLock);	if (relation->rd_rel->relkind != RELKIND_RELATION)		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("inherited relation \"%s\" is not a table",						inhRelation->relation->relname)));	/*	 * Check for SELECT privilages	 */	aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(),								  ACL_SELECT);	if (aclresult != ACLCHECK_OK)		aclcheck_error(aclresult, ACL_KIND_CLASS,					   RelationGetRelationName(relation));	tupleDesc = RelationGetDescr(relation);	constr = tupleDesc->constr;	/*	 * Insert the inherited attributes into the cxt for the new table	 * definition.	 */	for (parent_attno = 1; parent_attno <= tupleDesc->natts;		 parent_attno++)	{		Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];		char	   *attributeName = NameStr(attribute->attname);		ColumnDef  *def;		TypeName   *typename;		/*		 * Ignore dropped columns in the parent.		 */		if (attribute->attisdropped)			continue;		/*		 * Create a new inherited column.		 *		 * For constraints, ONLY the NOT NULL constraint is inherited by the		 * new column definition per SQL99.		 */		def = makeNode(ColumnDef);		def->colname = pstrdup(attributeName);		typename = makeNode(TypeName);		typename->typeid = attribute->atttypid;		typename->typmod = attribute->atttypmod;		def->typename = typename;		def->inhcount = 0;		def->is_local = false;		def->is_not_null = attribute->attnotnull;		def->raw_default = NULL;		def->cooked_default = NULL;		def->constraints = NIL;		def->support = NULL;		/*		 * Add to column list		 */		cxt->columns = lappend(cxt->columns, def);		/*		 * Copy default if any, and the default has been requested		 */		if (attribute->atthasdef && inhRelation->including_defaults)		{			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.			 */			def->cooked_default = pstrdup(this_default);		}	}	/*	 * 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);}static voidtransformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt){	IndexStmt  *index;	List	   *indexlist = NIL;	ListCell   *listptr;	ListCell   *l;	/*	 * Run through the constraints that need to generate an index. For PRIMARY	 * KEY, mark each column as NOT NULL and create an index. For UNIQUE,	 * create an index as for PRIMARY KEY, but do not insist on NOT NULL.	 */	foreach(listptr, cxt->ixconstraints)	{		Constraint *constraint = lfirst(listptr);		ListCell   *keys;		IndexElem  *iparam;		Assert(IsA(constraint, Constraint));		Assert((constraint->contype == CONSTR_PRIMARY)			   || (constraint->contype == CONSTR_UNIQUE));		index = makeNode(IndexStmt);		index->unique = true;		index->primary = (constraint->contype == CONSTR_PRIMARY);		if (index->primary)		{			if (cxt->pkey != NULL)				ereport(ERROR,						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),						 errmsg("multiple primary keys for table \"%s\" are not allowed",								cxt->relation->relname)));			cxt->pkey = index;			/*			 * In ALTER TABLE case, a primary index might already exist, but			 * DefineIndex will check for it.			 */		}		index->isconstraint = true;		if (constraint->name != NULL)			index->idxname = pstrdup(constraint->name);		else			index->idxname = NULL;		/* DefineIndex will choose name */		index->relation = cxt->relation;		index->accessMethod = DEFAULT_INDEX_TYPE;		index->tableSpace = constraint->indexspace;		index->indexParams = NIL;		index->whereClause = NULL;		/*		 * Make sure referenced keys exist.  If we are making a PRIMARY KEY		 * index, also make sure they are NOT NULL, if possible. (Although we		 * could leave it to DefineIndex to mark the columns NOT NULL, it's		 * more efficient to get it right the first time.)		 */		foreach(keys, constraint->keys)		{			char	   *key = strVal(lfirst(keys));			bool		found = false;			ColumnDef  *column = NULL;			ListCell   *columns;			foreach(columns, cxt->columns)			{				column = (ColumnDef *) lfirst(columns);				Assert(IsA(column, ColumnDef));				if (strcmp(column->colname, key) == 0)				{					found = true;					break;				}			}			if (found)			{				/* found column in the new table; force it to be NOT NULL */				if (constraint->contype == CONSTR_PRIMARY)					column->is_not_null = TRUE;			}			else if (SystemAttributeByName(key, cxt->hasoids) != NULL)			{				/*				 * column will be a system column in the new table, so accept				 * it.	System columns can't ever be null, so no need to worry				 * about PRIMARY/NOT NULL constraint.				 */				found = true;			}			else if (cxt->inhRelations)			{				/* try inherited tables */				ListCell   *inher;				foreach(inher, cxt->inhRelations)				{					RangeVar   *inh = (RangeVar *) lfirst(inher);					Relation	rel;					int			count;					Assert(IsA(inh, RangeVar));					rel = heap_openrv(inh, AccessShareLock);					if (rel->rd_rel->relkind != RELKIND_RELATION)						ereport(ERROR,								(errcode(ERRCODE_WRONG_OBJECT_TYPE),						   errmsg("inherited relation \"%s\" is not a table",								  inh->relname)));					for (count = 0; count < rel->rd_att->natts; count++)					{						Form_pg_attribute inhattr = rel->rd_att->attrs[count];						char	   *inhname = NameStr(inhattr->attname);						if (inhattr->attisdropped)							continue;						if (strcmp(key, inhname) == 0)						{							found = true;							/*							 * We currently have no easy way to force an							 * inherited column to be NOT NULL at creation, if							 * its parent wasn't so already. We leave it to							 * DefineIndex to fix things up in this case.							 */							break;						}					}					heap_close(rel, NoLock);					if (found)						break;				}			}			/*			 * In the ALTER TABLE case, don't complain about index keys not			 * created in the command; they may well exist already.			 * DefineIndex will complain about them if not, and will also take			 * care of marking them NOT NULL.			 */			if (!found && !cxt->isalter)				ereport(ERROR,						(errcode(ERRCODE_UNDEFINED_COLUMN),						 errmsg("column \"%s\" named in key does not exist",								key)));			/* Check for PRIMARY KEY(foo, foo) */			foreach(columns, index->indexParams)			{				iparam = (IndexElem *) lfirst(columns);				if (iparam->name && strcmp(key, iparam->name) == 0)				{					if (index->primary)						ereport(ERROR,								(errcode(ERRCODE_DUPLICATE_COLUMN),								 errmsg("column \"%s\" appears twice in primary key constraint",										key)));					else						ereport(ERROR,								(errcode(ERRCODE_DUPLICATE_COLUMN),								 errmsg("column \"%s\" appears twice in unique constraint",										key)));

⌨️ 快捷键说明

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