⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rewritehandler.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
		sub_action->commandType != CMD_UTILITY)	{		sub_action = (Query *) ResolveNew((Node *) sub_action,										  new_varno,										  0,										  rt_fetch(new_varno,												   sub_action->rtable),										  parsetree->targetList,										  event,										  current_varno);		if (sub_action_ptr)			*sub_action_ptr = sub_action;		else			rule_action = sub_action;	}	return rule_action;}/* * Copy the query's jointree list, and optionally attempt to remove any * occurrence of the given rt_index as a top-level join item (we do not look * for it within join items; this is OK because we are only expecting to find * it as an UPDATE or DELETE target relation, which will be at the top level * of the join).  Returns modified jointree list --- this is a separate copy * sharing no nodes with the original. */static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index){	List	   *newjointree = copyObject(parsetree->jointree->fromlist);	ListCell   *l;	if (removert)	{		foreach(l, newjointree)		{			RangeTblRef *rtr = lfirst(l);			if (IsA(rtr, RangeTblRef) &&				rtr->rtindex == rt_index)			{				newjointree = list_delete_ptr(newjointree, rtr);				/*				 * foreach is safe because we exit loop after list_delete...				 */				break;			}		}	}	return newjointree;}/* * rewriteTargetList - rewrite INSERT/UPDATE targetlist into standard form * * This has the following responsibilities: * * 1. For an INSERT, add tlist entries to compute default values for any * attributes that have defaults and are not assigned to in the given tlist. * (We do not insert anything for default-less attributes, however.  The * planner will later insert NULLs for them, but there's no reason to slow * down rewriter processing with extra tlist nodes.)  Also, for both INSERT * and UPDATE, replace explicit DEFAULT specifications with column default * expressions. * * 2. Merge multiple entries for the same target attribute, or declare error * if we can't.  Multiple entries are only allowed for INSERT/UPDATE of * portions of an array or record field, for example *			UPDATE table SET foo[2] = 42, foo[4] = 43; * We can merge such operations into a single assignment op.  Essentially, * the expression we want to produce in this case is like *		foo = array_set(array_set(foo, 2, 42), 4, 43) * * 3. Sort the tlist into standard order: non-junk fields in order by resno, * then junk fields (these in no particular order). * * We must do items 1 and 2 before firing rewrite rules, else rewritten * references to NEW.foo will produce wrong or incomplete results.	Item 3 * is not needed for rewriting, but will be needed by the planner, and we * can do it essentially for free while handling items 1 and 2. */static voidrewriteTargetList(Query *parsetree, Relation target_relation){	CmdType		commandType = parsetree->commandType;	TargetEntry **new_tles;	List	   *new_tlist = NIL;	List	   *junk_tlist = NIL;	Form_pg_attribute att_tup;	int			attrno,				next_junk_attrno,				numattrs;	ListCell   *temp;	/*	 * We process the normal (non-junk) attributes by scanning the input tlist	 * once and transferring TLEs into an array, then scanning the array to	 * build an output tlist.  This avoids O(N^2) behavior for large numbers	 * of attributes.	 *	 * Junk attributes are tossed into a separate list during the same tlist	 * scan, then appended to the reconstructed tlist.	 */	numattrs = RelationGetNumberOfAttributes(target_relation);	new_tles = (TargetEntry **) palloc0(numattrs * sizeof(TargetEntry *));	next_junk_attrno = numattrs + 1;	foreach(temp, parsetree->targetList)	{		TargetEntry *old_tle = (TargetEntry *) lfirst(temp);		if (!old_tle->resjunk)		{			/* Normal attr: stash it into new_tles[] */			attrno = old_tle->resno;			if (attrno < 1 || attrno > numattrs)				elog(ERROR, "bogus resno %d in targetlist", attrno);			att_tup = target_relation->rd_att->attrs[attrno - 1];			/* We can (and must) ignore deleted attributes */			if (att_tup->attisdropped)				continue;			/* Merge with any prior assignment to same attribute */			new_tles[attrno - 1] =				process_matched_tle(old_tle,									new_tles[attrno - 1],									NameStr(att_tup->attname));		}		else		{			/*			 * Copy all resjunk tlist entries to junk_tlist, and assign them			 * resnos above the last real resno.			 *			 * Typical junk entries include ORDER BY or GROUP BY expressions			 * (are these actually possible in an INSERT or UPDATE?), system			 * attribute references, etc.			 */			/* Get the resno right, but don't copy unnecessarily */			if (old_tle->resno != next_junk_attrno)			{				old_tle = flatCopyTargetEntry(old_tle);				old_tle->resno = next_junk_attrno;			}			junk_tlist = lappend(junk_tlist, old_tle);			next_junk_attrno++;		}	}	for (attrno = 1; attrno <= numattrs; attrno++)	{		TargetEntry *new_tle = new_tles[attrno - 1];		att_tup = target_relation->rd_att->attrs[attrno - 1];		/* We can (and must) ignore deleted attributes */		if (att_tup->attisdropped)			continue;		/*		 * Handle the two cases where we need to insert a default expression:		 * it's an INSERT and there's no tlist entry for the column, or the		 * tlist entry is a DEFAULT placeholder node.		 */		if ((new_tle == NULL && commandType == CMD_INSERT) ||			(new_tle && new_tle->expr && IsA(new_tle->expr, SetToDefault)))		{			Node	   *new_expr;			new_expr = build_column_default(target_relation, attrno);			/*			 * If there is no default (ie, default is effectively NULL), we			 * can omit the tlist entry in the INSERT case, since the planner			 * can insert a NULL for itself, and there's no point in spending			 * any more rewriter cycles on the entry.  But in the UPDATE case			 * we've got to explicitly set the column to NULL.			 */			if (!new_expr)			{				if (commandType == CMD_INSERT)					new_tle = NULL;				else				{					new_expr = (Node *) makeConst(att_tup->atttypid,												  att_tup->attlen,												  (Datum) 0,												  true, /* isnull */												  att_tup->attbyval);					/* this is to catch a NOT NULL domain constraint */					new_expr = coerce_to_domain(new_expr,												InvalidOid,												att_tup->atttypid,												COERCE_IMPLICIT_CAST,												false,												false);				}			}			if (new_expr)				new_tle = makeTargetEntry((Expr *) new_expr,										  attrno,										  pstrdup(NameStr(att_tup->attname)),										  false);		}		if (new_tle)			new_tlist = lappend(new_tlist, new_tle);	}	pfree(new_tles);	parsetree->targetList = list_concat(new_tlist, junk_tlist);}/* * Convert a matched TLE from the original tlist into a correct new TLE. * * This routine detects and handles multiple assignments to the same target * attribute.  (The attribute name is needed only for error messages.) */static TargetEntry *process_matched_tle(TargetEntry *src_tle,					TargetEntry *prior_tle,					const char *attrName){	TargetEntry *result;	Node	   *src_expr;	Node	   *prior_expr;	Node	   *src_input;	Node	   *prior_input;	Node	   *priorbottom;	Node	   *newexpr;	if (prior_tle == NULL)	{		/*		 * Normal case where this is the first assignment to the attribute.		 */		return src_tle;	}	/*----------	 * Multiple assignments to same attribute.	Allow only if all are	 * FieldStore or ArrayRef assignment operations.  This is a bit	 * tricky because what we may actually be looking at is a nest of	 * such nodes; consider	 *		UPDATE tab SET col.fld1.subfld1 = x, col.fld2.subfld2 = y	 * The two expressions produced by the parser will look like	 *		FieldStore(col, fld1, FieldStore(placeholder, subfld1, x))	 *		FieldStore(col, fld2, FieldStore(placeholder, subfld2, x))	 * However, we can ignore the substructure and just consider the top	 * FieldStore or ArrayRef from each assignment, because it works to	 * combine these as	 *		FieldStore(FieldStore(col, fld1,	 *							  FieldStore(placeholder, subfld1, x)),	 *				   fld2, FieldStore(placeholder, subfld2, x))	 * Note the leftmost expression goes on the inside so that the	 * assignments appear to occur left-to-right.	 *	 * For FieldStore, instead of nesting we can generate a single	 * FieldStore with multiple target fields.	We must nest when	 * ArrayRefs are involved though.	 *----------	 */	src_expr = (Node *) src_tle->expr;	prior_expr = (Node *) prior_tle->expr;	src_input = get_assignment_input(src_expr);	prior_input = get_assignment_input(prior_expr);	if (src_input == NULL ||		prior_input == NULL ||		exprType(src_expr) != exprType(prior_expr))		ereport(ERROR,				(errcode(ERRCODE_SYNTAX_ERROR),				 errmsg("multiple assignments to same column \"%s\"",						attrName)));	/*	 * Prior TLE could be a nest of assignments if we do this more than once.	 */	priorbottom = prior_input;	for (;;)	{		Node	   *newbottom = get_assignment_input(priorbottom);		if (newbottom == NULL)			break;				/* found the original Var reference */		priorbottom = newbottom;	}	if (!equal(priorbottom, src_input))		ereport(ERROR,				(errcode(ERRCODE_SYNTAX_ERROR),				 errmsg("multiple assignments to same column \"%s\"",						attrName)));	/*	 * Looks OK to nest 'em.	 */	if (IsA(src_expr, FieldStore))	{		FieldStore *fstore = makeNode(FieldStore);		if (IsA(prior_expr, FieldStore))		{			/* combine the two */			memcpy(fstore, prior_expr, sizeof(FieldStore));			fstore->newvals =				list_concat(list_copy(((FieldStore *) prior_expr)->newvals),							list_copy(((FieldStore *) src_expr)->newvals));			fstore->fieldnums =				list_concat(list_copy(((FieldStore *) prior_expr)->fieldnums),							list_copy(((FieldStore *) src_expr)->fieldnums));		}		else		{			/* general case, just nest 'em */			memcpy(fstore, src_expr, sizeof(FieldStore));			fstore->arg = (Expr *) prior_expr;		}		newexpr = (Node *) fstore;	}	else if (IsA(src_expr, ArrayRef))	{		ArrayRef   *aref = makeNode(ArrayRef);		memcpy(aref, src_expr, sizeof(ArrayRef));		aref->refexpr = (Expr *) prior_expr;		newexpr = (Node *) aref;	}	else	{		elog(ERROR, "can't happen");		newexpr = NULL;	}	result = flatCopyTargetEntry(src_tle);	result->expr = (Expr *) newexpr;	return result;}/* * If node is an assignment node, return its input; else return NULL */static Node *get_assignment_input(Node *node){	if (node == NULL)		return NULL;	if (IsA(node, FieldStore))	{		FieldStore *fstore = (FieldStore *) node;		return (Node *) fstore->arg;	}	else if (IsA(node, ArrayRef))	{		ArrayRef   *aref = (ArrayRef *) node;		if (aref->refassgnexpr == NULL)			return NULL;		return (Node *) aref->refexpr;	}	return NULL;}/* * Make an expression tree for the default value for a column. * * If there is no default, return a NULL instead. */Node *build_column_default(Relation rel, int attrno){	TupleDesc	rd_att = rel->rd_att;	Form_pg_attribute att_tup = rd_att->attrs[attrno - 1];	Oid			atttype = att_tup->atttypid;	int32		atttypmod = att_tup->atttypmod;	Node	   *expr = NULL;	Oid			exprtype;	/*	 * Scan to see if relation has a default for this column.	 */	if (rd_att->constr && rd_att->constr->num_defval > 0)	{		AttrDefault *defval = rd_att->constr->defval;		int			ndef = rd_att->constr->num_defval;		while (--ndef >= 0)		{			if (attrno == defval[ndef].adnum)			{				/*				 * Found it, convert string representation to node tree.				 */				expr = stringToNode(defval[ndef].adbin);				break;			}		}

⌨️ 快捷键说明

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