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

📄 rewritemanip.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * rewriteManip.c * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.92.2.3 2006/01/06 20:11:18 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_type.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/tlist.h"#include "parser/parsetree.h"#include "parser/parse_coerce.h"#include "parser/parse_relation.h"#include "rewrite/rewriteManip.h"#include "utils/lsyscache.h"typedef struct{	int			sublevels_up;} checkExprHasAggs_context;static bool checkExprHasAggs_walker(Node *node,						checkExprHasAggs_context *context);static bool checkExprHasSubLink_walker(Node *node, void *context);static Relids offset_relid_set(Relids relids, int offset);static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);/* * checkExprHasAggs - *	Check if an expression contains an aggregate function call. * * The objective of this routine is to detect whether there are aggregates * belonging to the initial query level.  Aggregates belonging to subqueries * or outer queries do NOT cause a true result.  We must recurse into * subqueries to detect outer-reference aggregates that logically belong to * the initial query level. */boolcheckExprHasAggs(Node *node){	checkExprHasAggs_context context;	context.sublevels_up = 0;	/*	 * 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,										   checkExprHasAggs_walker,										   (void *) &context,										   0);}static boolcheckExprHasAggs_walker(Node *node, checkExprHasAggs_context *context){	if (node == NULL)		return false;	if (IsA(node, Aggref))	{		if (((Aggref *) node)->agglevelsup == context->sublevels_up)			return true;		/* abort the tree traversal and return true */		/* else fall through to examine argument */	}	if (IsA(node, Query))	{		/* Recurse into subselects */		bool		result;		context->sublevels_up++;		result = query_tree_walker((Query *) node,								   checkExprHasAggs_walker,								   (void *) context, 0);		context->sublevels_up--;		return result;	}	return expression_tree_walker(node, checkExprHasAggs_walker,								  (void *) context);}/* * checkExprHasSubLink - *	Check if an expression contains a SubLink. */boolcheckExprHasSubLink(Node *node){	/*	 * If a Query is passed, examine it --- but we need not recurse into	 * sub-Queries.	 */	return query_or_expression_tree_walker(node,										   checkExprHasSubLink_walker,										   NULL,										   QTW_IGNORE_RT_SUBQUERIES);}static boolcheckExprHasSubLink_walker(Node *node, void *context){	if (node == NULL)		return false;	if (IsA(node, SubLink))		return true;			/* abort the tree traversal and return true */	return expression_tree_walker(node, checkExprHasSubLink_walker, context);}/* * OffsetVarNodes - adjust Vars when appending one query's RT to another * * Find all Var nodes in the given tree with varlevelsup == sublevels_up, * and increment their varno fields (rangetable indexes) by 'offset'. * The varnoold fields are adjusted similarly.	Also, adjust other nodes * that contain rangetable indexes, such as RangeTblRef and JoinExpr. * * NOTE: although this has the form of a walker, we cheat and modify the * nodes in-place.	The given expression tree should have been copied * earlier to ensure that no unwanted side-effects occur! */typedef struct{	int			offset;	int			sublevels_up;} OffsetVarNodes_context;static boolOffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context){	if (node == NULL)		return false;	if (IsA(node, Var))	{		Var		   *var = (Var *) node;		if (var->varlevelsup == context->sublevels_up)		{			var->varno += context->offset;			var->varnoold += context->offset;		}		return false;	}	if (IsA(node, RangeTblRef))	{		RangeTblRef *rtr = (RangeTblRef *) node;		if (context->sublevels_up == 0)			rtr->rtindex += context->offset;		/* the subquery itself is visited separately */		return false;	}	if (IsA(node, JoinExpr))	{		JoinExpr   *j = (JoinExpr *) node;		if (context->sublevels_up == 0)			j->rtindex += context->offset;		/* fall through to examine children */	}	if (IsA(node, InClauseInfo))	{		InClauseInfo *ininfo = (InClauseInfo *) node;		if (context->sublevels_up == 0)		{			ininfo->lefthand = offset_relid_set(ininfo->lefthand,												context->offset);			ininfo->righthand = offset_relid_set(ininfo->righthand,												 context->offset);		}		/* fall through to examine children */	}	if (IsA(node, Query))	{		/* Recurse into subselects */		bool		result;		context->sublevels_up++;		result = query_tree_walker((Query *) node, OffsetVarNodes_walker,								   (void *) context, 0);		context->sublevels_up--;		return result;	}	return expression_tree_walker(node, OffsetVarNodes_walker,								  (void *) context);}voidOffsetVarNodes(Node *node, int offset, int sublevels_up){	OffsetVarNodes_context context;	context.offset = offset;	context.sublevels_up = sublevels_up;	/*	 * Must be prepared to start with a Query or a bare expression tree; if	 * it's a Query, go straight to query_tree_walker to make sure that	 * sublevels_up doesn't get incremented prematurely.	 */	if (node && IsA(node, Query))	{		Query	   *qry = (Query *) node;		/*		 * If we are starting at a Query, and sublevels_up is zero, then we		 * must also fix rangetable indexes in the Query itself --- namely		 * resultRelation and rowMarks entries.  sublevels_up cannot be zero		 * when recursing into a subquery, so there's no need to have the same		 * logic inside OffsetVarNodes_walker.		 */		if (sublevels_up == 0)		{			ListCell   *l;			if (qry->resultRelation)				qry->resultRelation += offset;			foreach(l, qry->rowMarks)				lfirst_int(l) += offset;		}		query_tree_walker(qry, OffsetVarNodes_walker,						  (void *) &context, 0);	}	else		OffsetVarNodes_walker(node, &context);}static Relidsoffset_relid_set(Relids relids, int offset){	Relids		result = NULL;	Relids		tmprelids;	int			rtindex;	tmprelids = bms_copy(relids);	while ((rtindex = bms_first_member(tmprelids)) >= 0)		result = bms_add_member(result, rtindex + offset);	bms_free(tmprelids);	return result;}/* * ChangeVarNodes - adjust Var nodes for a specific change of RT index * * Find all Var nodes in the given tree belonging to a specific relation * (identified by sublevels_up and rt_index), and change their varno fields * to 'new_index'.	The varnoold fields are changed too.  Also, adjust other * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr. * * NOTE: although this has the form of a walker, we cheat and modify the * nodes in-place.	The given expression tree should have been copied * earlier to ensure that no unwanted side-effects occur! */typedef struct{	int			rt_index;	int			new_index;	int			sublevels_up;} ChangeVarNodes_context;static boolChangeVarNodes_walker(Node *node, ChangeVarNodes_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->varno = context->new_index;			var->varnoold = context->new_index;		}		return false;	}	if (IsA(node, RangeTblRef))	{		RangeTblRef *rtr = (RangeTblRef *) node;		if (context->sublevels_up == 0 &&			rtr->rtindex == context->rt_index)			rtr->rtindex = context->new_index;		/* the subquery itself is visited separately */		return false;	}	if (IsA(node, JoinExpr))	{		JoinExpr   *j = (JoinExpr *) node;		if (context->sublevels_up == 0 &&			j->rtindex == context->rt_index)			j->rtindex = context->new_index;		/* fall through to examine children */	}	if (IsA(node, InClauseInfo))	{		InClauseInfo *ininfo = (InClauseInfo *) node;		if (context->sublevels_up == 0)		{			ininfo->lefthand = adjust_relid_set(ininfo->lefthand,												context->rt_index,												context->new_index);			ininfo->righthand = adjust_relid_set(ininfo->righthand,												 context->rt_index,												 context->new_index);		}		/* fall through to examine children */	}	if (IsA(node, Query))	{		/* Recurse into subselects */		bool		result;		context->sublevels_up++;		result = query_tree_walker((Query *) node, ChangeVarNodes_walker,								   (void *) context, 0);		context->sublevels_up--;		return result;	}	return expression_tree_walker(node, ChangeVarNodes_walker,								  (void *) context);}voidChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up){	ChangeVarNodes_context context;	context.rt_index = rt_index;	context.new_index = new_index;	context.sublevels_up = sublevels_up;	/*	 * Must be prepared to start with a Query or a bare expression tree; if	 * it's a Query, go straight to query_tree_walker to make sure that	 * sublevels_up doesn't get incremented prematurely.	 */	if (node && IsA(node, Query))	{		Query	   *qry = (Query *) node;		/*		 * If we are starting at a Query, and sublevels_up is zero, then we		 * must also fix rangetable indexes in the Query itself --- namely		 * resultRelation and rowMarks entries.  sublevels_up cannot be zero		 * when recursing into a subquery, so there's no need to have the same		 * logic inside ChangeVarNodes_walker.		 */		if (sublevels_up == 0)		{			ListCell   *l;			if (qry->resultRelation == rt_index)				qry->resultRelation = new_index;			foreach(l, qry->rowMarks)			{				if (lfirst_int(l) == rt_index)					lfirst_int(l) = new_index;			}		}		query_tree_walker(qry, ChangeVarNodes_walker,						  (void *) &context, 0);	}	else		ChangeVarNodes_walker(node, &context);}/* * Substitute newrelid for oldrelid in a Relid set */static Relidsadjust_relid_set(Relids relids, int oldrelid, int newrelid){	if (bms_is_member(oldrelid, relids))	{		/* Ensure we have a modifiable copy */		relids = bms_copy(relids);		/* Remove old, add new */		relids = bms_del_member(relids, oldrelid);		relids = bms_add_member(relids, newrelid);	}	return relids;}/* * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree * * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up, * and add delta_sublevels_up to their varlevelsup value.  This is needed when * an expression that's correct for some nesting level is inserted into a * subquery.  Ordinarily the initial call has min_sublevels_up == 0 so that * all Vars are affected.  The point of min_sublevels_up is that we can * increment it when we recurse into a sublink, so that local variables in * that sublink are not affected, only outer references to vars that belong * to the expression's original query level or parents thereof. * * Aggref nodes are adjusted similarly. * * NOTE: although this has the form of a walker, we cheat and modify the * Var nodes in-place.	The given expression tree should have been copied * earlier to ensure that no unwanted side-effects occur! */typedef struct{	int			delta_sublevels_up;	int			min_sublevels_up;} IncrementVarSublevelsUp_context;static boolIncrementVarSublevelsUp_walker(Node *node,							   IncrementVarSublevelsUp_context *context){	if (node == NULL)		return false;	if (IsA(node, Var))	{		Var		   *var = (Var *) node;		if (var->varlevelsup >= context->min_sublevels_up)			var->varlevelsup += context->delta_sublevels_up;		return false;			/* done here */	}	if (IsA(node, Aggref))	{		Aggref	   *agg = (Aggref *) node;		if (agg->agglevelsup >= context->min_sublevels_up)			agg->agglevelsup += context->delta_sublevels_up;		/* fall through to recurse into argument */	}	if (IsA(node, Query))	{		/* Recurse into subselects */		bool		result;		context->min_sublevels_up++;		result = query_tree_walker((Query *) node,								   IncrementVarSublevelsUp_walker,								   (void *) context, 0);		context->min_sublevels_up--;		return result;	}	return expression_tree_walker(node, IncrementVarSublevelsUp_walker,								  (void *) context);}voidIncrementVarSublevelsUp(Node *node, int delta_sublevels_up,						int min_sublevels_up){	IncrementVarSublevelsUp_context context;	context.delta_sublevels_up = delta_sublevels_up;	context.min_sublevels_up = min_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.	 */	query_or_expression_tree_walker(node,									IncrementVarSublevelsUp_walker,									(void *) &context,									0);}/* * rangeTableEntry_used - detect whether an RTE is referenced somewhere *	in var nodes or join or setOp trees of a query or expression.

⌨️ 快捷键说明

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