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

📄 rewritemanip.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
 */typedef struct{	int			rt_index;	int			sublevels_up;} rangeTableEntry_used_context;static boolrangeTableEntry_used_walker(Node *node,							rangeTableEntry_used_context *context){	if (node == NULL)		return false;	if (IsA(node, Var))	{		Var		   *var = (Var *) node;		if (var->varlevelsup == context->sublevels_up &&			var->varno == context->rt_index)			return true;		return false;	}	if (IsA(node, RangeTblRef))	{		RangeTblRef *rtr = (RangeTblRef *) node;		if (rtr->rtindex == context->rt_index &&			context->sublevels_up == 0)			return true;		/* the subquery itself is visited separately */		return false;	}	if (IsA(node, JoinExpr))	{		JoinExpr   *j = (JoinExpr *) node;		if (j->rtindex == context->rt_index &&			context->sublevels_up == 0)			return true;		/* fall through to examine children */	}	if (IsA(node, InClauseInfo))	{		InClauseInfo *ininfo = (InClauseInfo *) node;		if (context->sublevels_up == 0 &&			(bms_is_member(context->rt_index, ininfo->lefthand) ||			 bms_is_member(context->rt_index, ininfo->righthand)))			return true;		/* fall through to examine children */	}	if (IsA(node, Query))	{		/* Recurse into subselects */		bool		result;		context->sublevels_up++;		result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,								   (void *) context, 0);		context->sublevels_up--;		return result;	}	return expression_tree_walker(node, rangeTableEntry_used_walker,								  (void *) context);}boolrangeTableEntry_used(Node *node, int rt_index, int sublevels_up){	rangeTableEntry_used_context context;	context.rt_index = rt_index;	context.sublevels_up = sublevels_up;	/*	 * Must be prepared to start with a Query or a bare expression tree; if	 * it's a Query, we don't want to increment sublevels_up.	 */	return query_or_expression_tree_walker(node,										   rangeTableEntry_used_walker,										   (void *) &context,										   0);}/* * attribute_used - *	Check if a specific attribute number of a RTE is used *	somewhere in the query or expression. */typedef struct{	int			rt_index;	int			attno;	int			sublevels_up;} attribute_used_context;static boolattribute_used_walker(Node *node,					  attribute_used_context *context){	if (node == NULL)		return false;	if (IsA(node, Var))	{		Var		   *var = (Var *) node;		if (var->varlevelsup == context->sublevels_up &&			var->varno == context->rt_index &&			var->varattno == context->attno)			return true;		return false;	}	if (IsA(node, Query))	{		/* Recurse into subselects */		bool		result;		context->sublevels_up++;		result = query_tree_walker((Query *) node, attribute_used_walker,								   (void *) context, 0);		context->sublevels_up--;		return result;	}	return expression_tree_walker(node, attribute_used_walker,								  (void *) context);}boolattribute_used(Node *node, int rt_index, int attno, int sublevels_up){	attribute_used_context context;	context.rt_index = rt_index;	context.attno = attno;	context.sublevels_up = sublevels_up;	/*	 * Must be prepared to start with a Query or a bare expression tree; if	 * it's a Query, we don't want to increment sublevels_up.	 */	return query_or_expression_tree_walker(node,										   attribute_used_walker,										   (void *) &context,										   0);}/* * If the given Query is an INSERT ... SELECT construct, extract and * return the sub-Query node that represents the SELECT part.  Otherwise * return the given Query. * * If subquery_ptr is not NULL, then *subquery_ptr is set to the location * of the link to the SELECT subquery inside parsetree, or NULL if not an * INSERT ... SELECT. * * This is a hack needed because transformations on INSERT ... SELECTs that * appear in rule actions should be applied to the source SELECT, not to the * INSERT part.  Perhaps this can be cleaned up with redesigned querytrees. */Query *getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr){	Query	   *selectquery;	RangeTblEntry *selectrte;	RangeTblRef *rtr;	if (subquery_ptr)		*subquery_ptr = NULL;	if (parsetree == NULL)		return parsetree;	if (parsetree->commandType != CMD_INSERT)		return parsetree;	/*	 * Currently, this is ONLY applied to rule-action queries, and so we	 * expect to find the *OLD* and *NEW* placeholder entries in the given	 * query.  If they're not there, it must be an INSERT/SELECT in which	 * they've been pushed down to the SELECT.	 */	if (list_length(parsetree->rtable) >= 2 &&		strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,			   "*OLD*") == 0 &&		strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,			   "*NEW*") == 0)		return parsetree;	Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));	if (list_length(parsetree->jointree->fromlist) != 1)		elog(ERROR, "expected to find SELECT subquery");	rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);	Assert(IsA(rtr, RangeTblRef));	selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);	selectquery = selectrte->subquery;	if (!(selectquery && IsA(selectquery, Query) &&		  selectquery->commandType == CMD_SELECT))		elog(ERROR, "expected to find SELECT subquery");	if (list_length(selectquery->rtable) >= 2 &&		strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,			   "*OLD*") == 0 &&		strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,			   "*NEW*") == 0)	{		if (subquery_ptr)			*subquery_ptr = &(selectrte->subquery);		return selectquery;	}	elog(ERROR, "could not find rule placeholders");	return NULL;				/* not reached */}/* * Add the given qualifier condition to the query's WHERE clause */voidAddQual(Query *parsetree, Node *qual){	Node	   *copy;	if (qual == NULL)		return;	if (parsetree->commandType == CMD_UTILITY)	{		/*		 * There's noplace to put the qual on a utility statement.		 *		 * If it's a NOTIFY, silently ignore the qual; this means that the		 * NOTIFY will execute, whether or not there are any qualifying rows.		 * While clearly wrong, this is much more useful than refusing to		 * execute the rule at all, and extra NOTIFY events are harmless for		 * typical uses of NOTIFY.		 *		 * If it isn't a NOTIFY, error out, since unconditional execution of		 * other utility stmts is unlikely to be wanted.  (This case is not		 * currently allowed anyway, but keep the test for safety.)		 */		if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))			return;		else			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),			  errmsg("conditional utility statements are not implemented")));	}	if (parsetree->setOperations != NULL)	{		/*		 * There's noplace to put the qual on a setop statement, either. (This		 * could be fixed, but right now the planner simply ignores any qual		 * condition on a setop query.)		 */		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));	}	/* INTERSECT want's the original, but we need to copy - Jan */	copy = copyObject(qual);	parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,											   copy);	/*	 * We had better not have stuck an aggregate into the WHERE clause.	 */	Assert(!checkExprHasAggs(copy));	/*	 * Make sure query is marked correctly if added qual has sublinks. Need	 * not search qual when query is already marked.	 */	if (!parsetree->hasSubLinks)		parsetree->hasSubLinks = checkExprHasSubLink(copy);}/* * Invert the given clause and add it to the WHERE qualifications of the * given querytree.  Inversion means "x IS NOT TRUE", not just "NOT x", * else we will do the wrong thing when x evaluates to NULL. */voidAddInvertedQual(Query *parsetree, Node *qual){	BooleanTest *invqual;	if (qual == NULL)		return;	/* Need not copy input qual, because AddQual will... */	invqual = makeNode(BooleanTest);	invqual->arg = (Expr *) qual;	invqual->booltesttype = IS_NOT_TRUE;	AddQual(parsetree, (Node *) invqual);}/* * ResolveNew - replace Vars with corresponding items from a targetlist * * Vars matching target_varno and sublevels_up are replaced by the * entry with matching resno from targetlist, if there is one. * If not, we either change the unmatched Var's varno to update_varno * (when event == CMD_UPDATE) or replace it with a constant NULL. * * The caller must also provide target_rte, the RTE describing the target * relation.  This is needed to handle whole-row Vars referencing the target. * We expand such Vars into RowExpr constructs. * * Note: the business with inserted_sublink is needed to update hasSubLinks * in subqueries when the replacement adds a subquery inside a subquery. * Messy, isn't it?  We do not need to do similar pushups for hasAggs, * because it isn't possible for this transformation to insert a level-zero * aggregate reference into a subquery --- it could only insert outer aggs. */typedef struct{	int			target_varno;	int			sublevels_up;	RangeTblEntry *target_rte;	List	   *targetlist;	int			event;	int			update_varno;	bool		inserted_sublink;} ResolveNew_context;static Node *resolve_one_var(Var *var, ResolveNew_context *context){	TargetEntry *tle;	tle = get_tle_by_resno(context->targetlist, var->varattno);	if (tle == NULL)	{		/* Failed to find column in insert/update tlist */		if (context->event == CMD_UPDATE)		{			/* For update, just change unmatched var's varno */			var = (Var *) copyObject(var);			var->varno = context->update_varno;			var->varnoold = context->update_varno;			return (Node *) var;		}		else		{			/* Otherwise replace unmatched var with a null */			/* need coerce_to_domain in case of NOT NULL domain constraint */			return coerce_to_domain((Node *) makeNullConst(var->vartype),									InvalidOid,									var->vartype,									COERCE_IMPLICIT_CAST,									false,									false);		}	}	else	{		/* Make a copy of the tlist item to return */		Node	   *n = copyObject(tle->expr);		/* Adjust varlevelsup if tlist item is from higher query */		if (var->varlevelsup > 0)			IncrementVarSublevelsUp(n, var->varlevelsup, 0);		/* Report it if we are adding a sublink to query */		if (!context->inserted_sublink)			context->inserted_sublink = checkExprHasSubLink(n);		return n;	}}static Node *ResolveNew_mutator(Node *node, ResolveNew_context *context){	if (node == NULL)		return NULL;	if (IsA(node, Var))	{		Var		   *var = (Var *) node;		int			this_varno = (int) var->varno;		int			this_varlevelsup = (int) var->varlevelsup;		if (this_varno == context->target_varno &&			this_varlevelsup == context->sublevels_up)		{			if (var->varattno == InvalidAttrNumber)			{				/* Must expand whole-tuple reference into RowExpr */				RowExpr    *rowexpr;				List	   *fields;				/*				 * If generating an expansion for a var of a named rowtype				 * (ie, this is a plain relation RTE), then we must include				 * dummy items for dropped columns.  If the var is RECORD (ie,				 * this is a JOIN), then omit dropped columns.				 */				expandRTE(context->target_rte,						  this_varno, this_varlevelsup,						  (var->vartype != RECORDOID),						  NULL, &fields);				/* Adjust the generated per-field Vars... */				fields = (List *) ResolveNew_mutator((Node *) fields,													 context);				rowexpr = makeNode(RowExpr);				rowexpr->args = fields;				rowexpr->row_typeid = var->vartype;				rowexpr->row_format = COERCE_IMPLICIT_CAST;				return (Node *) rowexpr;			}			/* Normal case for scalar variable */			return resolve_one_var(var, context);		}		/* otherwise fall through to copy the var normally */	}	if (IsA(node, Query))	{		/* Recurse into RTE subquery or not-yet-planned sublink subquery */		Query	   *newnode;		bool		save_inserted_sublink;		context->sublevels_up++;		save_inserted_sublink = context->inserted_sublink;		context->inserted_sublink = false;		newnode = query_tree_mutator((Query *) node,									 ResolveNew_mutator,									 (void *) context,									 0);		newnode->hasSubLinks |= context->inserted_sublink;		context->inserted_sublink = save_inserted_sublink;		context->sublevels_up--;		return (Node *) newnode;	}	return expression_tree_mutator(node, ResolveNew_mutator,								   (void *) context);}Node *ResolveNew(Node *node, int target_varno, int sublevels_up,		   RangeTblEntry *target_rte,		   List *targetlist, int event, int update_varno){	Node	   *result;	ResolveNew_context context;	context.target_varno = target_varno;	context.sublevels_up = sublevels_up;	context.target_rte = target_rte;	context.targetlist = targetlist;	context.event = event;	context.update_varno = update_varno;	context.inserted_sublink = false;	/*	 * Must be prepared to start with a Query or a bare expression tree; if	 * it's a Query, we don't want to increment sublevels_up.	 */	result = query_or_expression_tree_mutator(node,											  ResolveNew_mutator,											  (void *) &context,											  0);	if (context.inserted_sublink)	{		if (IsA(result, Query))			((Query *) result)->hasSubLinks = true;		/*		 * Note: if we're called on a non-Query node then it's the caller's		 * responsibility to update hasSubLinks in the ancestor Query.		 * This is pretty fragile and perhaps should be rethought ...		 */	}	return result;}

⌨️ 快捷键说明

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