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

📄 rewritehandler.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
	}	if (expr == NULL)	{		/*		 * No per-column default, so look for a default for the type itself.		 */		expr = get_typdefault(atttype);	}	if (expr == NULL)		return NULL;			/* No default anywhere */	/*	 * Make sure the value is coerced to the target column type; this will	 * generally be true already, but there seem to be some corner cases	 * involving domain defaults where it might not be true. This should match	 * the parser's processing of non-defaulted expressions --- see	 * updateTargetListEntry().	 */	exprtype = exprType(expr);	expr = coerce_to_target_type(NULL,	/* no UNKNOWN params here */								 expr, exprtype,								 atttype, atttypmod,								 COERCION_ASSIGNMENT,								 COERCE_IMPLICIT_CAST);	if (expr == NULL)		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),				 errmsg("column \"%s\" is of type %s"						" but default expression is of type %s",						NameStr(att_tup->attname),						format_type_be(atttype),						format_type_be(exprtype)),			   errhint("You will need to rewrite or cast the expression.")));	return expr;}/* * matchLocks - *	  match the list of locks and returns the matching rules */static List *matchLocks(CmdType event,		   RuleLock *rulelocks,		   int varno,		   Query *parsetree){	List	   *matching_locks = NIL;	int			nlocks;	int			i;	if (rulelocks == NULL)		return NIL;	if (parsetree->commandType != CMD_SELECT)	{		if (parsetree->resultRelation != varno)			return NIL;	}	nlocks = rulelocks->numLocks;	for (i = 0; i < nlocks; i++)	{		RewriteRule *oneLock = rulelocks->rules[i];		if (oneLock->event == event)		{			if (parsetree->commandType != CMD_SELECT ||				(oneLock->attrno == -1 ?				 rangeTableEntry_used((Node *) parsetree, varno, 0) :				 attribute_used((Node *) parsetree,								varno, oneLock->attrno, 0)))				matching_locks = lappend(matching_locks, oneLock);		}	}	return matching_locks;}/* * ApplyRetrieveRule - expand an ON SELECT rule */static Query *ApplyRetrieveRule(Query *parsetree,				  RewriteRule *rule,				  int rt_index,				  bool relation_level,				  Relation relation,				  List *activeRIRs){	Query	   *rule_action;	RangeTblEntry *rte,			   *subrte;	if (list_length(rule->actions) != 1)		elog(ERROR, "expected just one rule action");	if (rule->qual != NULL)		elog(ERROR, "cannot handle qualified ON SELECT rule");	if (!relation_level)		elog(ERROR, "cannot handle per-attribute ON SELECT rule");	/*	 * Make a modifiable copy of the view query, and acquire needed locks on	 * the relations it mentions.	 */	rule_action = copyObject(linitial(rule->actions));	AcquireRewriteLocks(rule_action);	/*	 * Recursively expand any view references inside the view.	 */	rule_action = fireRIRrules(rule_action, activeRIRs);	/*	 * VIEWs are really easy --- just plug the view query in as a subselect,	 * replacing the relation's original RTE.	 */	rte = rt_fetch(rt_index, parsetree->rtable);	rte->rtekind = RTE_SUBQUERY;	rte->relid = InvalidOid;	rte->subquery = rule_action;	rte->inh = false;			/* must not be set for a subquery */	/*	 * We move the view's permission check data down to its rangetable. The	 * checks will actually be done against the *OLD* entry therein.	 */	subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);	Assert(subrte->relid == relation->rd_id);	subrte->requiredPerms = rte->requiredPerms;	subrte->checkAsUser = rte->checkAsUser;	rte->requiredPerms = 0;		/* no permission check on subquery itself */	rte->checkAsUser = InvalidOid;	/*	 * FOR UPDATE/SHARE of view?	 */	if (list_member_int(parsetree->rowMarks, rt_index))	{		/*		 * Remove the view from the list of rels that will actually be marked		 * FOR UPDATE/SHARE by the executor.  It will still be access- checked		 * for write access, though.		 */		parsetree->rowMarks = list_delete_int(parsetree->rowMarks, rt_index);		/*		 * Set up the view's referenced tables as if FOR UPDATE/SHARE.		 */		markQueryForLocking(rule_action, parsetree->forUpdate,							parsetree->rowNoWait, true);	}	return parsetree;}/* * Recursively mark all relations used by a view as FOR UPDATE/SHARE. * * This may generate an invalid query, eg if some sub-query uses an * aggregate.  We leave it to the planner to detect that. * * NB: this must agree with the parser's transformLocking() routine. */static voidmarkQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew){	Index		rti = 0;	ListCell   *l;	if (qry->rowMarks)	{		if (forUpdate != qry->forUpdate)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),			errmsg("cannot use both FOR UPDATE and FOR SHARE in one query")));		if (noWait != qry->rowNoWait)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("cannot use both wait and NOWAIT in one query")));	}	qry->forUpdate = forUpdate;	qry->rowNoWait = noWait;	foreach(l, qry->rtable)	{		RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);		rti++;		/* Ignore OLD and NEW entries if we are at top level of view */		if (skipOldNew &&			(rti == PRS2_OLD_VARNO || rti == PRS2_NEW_VARNO))			continue;		if (rte->rtekind == RTE_RELATION)		{			qry->rowMarks = list_append_unique_int(qry->rowMarks, rti);			rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;		}		else if (rte->rtekind == RTE_SUBQUERY)		{			/* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */			markQueryForLocking(rte->subquery, forUpdate, noWait, false);		}	}}/* * fireRIRonSubLink - *	Apply fireRIRrules() to each SubLink (subselect in expression) found *	in the given tree. * * NOTE: although this has the form of a walker, we cheat and modify the * SubLink nodes in-place.	It is caller's responsibility to ensure that * no unwanted side-effects occur! * * This is unlike most of the other routines that recurse into subselects, * because we must take control at the SubLink node in order to replace * the SubLink's subselect link with the possibly-rewritten subquery. */static boolfireRIRonSubLink(Node *node, List *activeRIRs){	if (node == NULL)		return false;	if (IsA(node, SubLink))	{		SubLink    *sub = (SubLink *) node;		/* Do what we came for */		sub->subselect = (Node *) fireRIRrules((Query *) sub->subselect,											   activeRIRs);		/* Fall through to process lefthand args of SubLink */	}	/*	 * Do NOT recurse into Query nodes, because fireRIRrules already processed	 * subselects of subselects for us.	 */	return expression_tree_walker(node, fireRIRonSubLink,								  (void *) activeRIRs);}/* * fireRIRrules - *	Apply all RIR rules on each rangetable entry in a query */static Query *fireRIRrules(Query *parsetree, List *activeRIRs){	int			rt_index;	/*	 * don't try to convert this into a foreach loop, because rtable list can	 * get changed each time through...	 */	rt_index = 0;	while (rt_index < list_length(parsetree->rtable))	{		RangeTblEntry *rte;		Relation	rel;		List	   *locks;		RuleLock   *rules;		RewriteRule *rule;		int			i;		++rt_index;		rte = rt_fetch(rt_index, parsetree->rtable);		/*		 * A subquery RTE can't have associated rules, so there's nothing to		 * do to this level of the query, but we must recurse into the		 * subquery to expand any rule references in it.		 */		if (rte->rtekind == RTE_SUBQUERY)		{			rte->subquery = fireRIRrules(rte->subquery, activeRIRs);			continue;		}		/*		 * Joins and other non-relation RTEs can be ignored completely.		 */		if (rte->rtekind != RTE_RELATION)			continue;		/*		 * If the table is not referenced in the query, then we ignore it.		 * This prevents infinite expansion loop due to new rtable entries		 * inserted by expansion of a rule. A table is referenced if it is		 * part of the join set (a source table), or is referenced by any Var		 * nodes, or is the result table.		 */		if (rt_index != parsetree->resultRelation &&			!rangeTableEntry_used((Node *) parsetree, rt_index, 0))			continue;		/*		 * We can use NoLock here since either the parser or		 * AcquireRewriteLocks should have locked the rel already.		 */		rel = heap_open(rte->relid, NoLock);		/*		 * Collect the RIR rules that we must apply		 */		rules = rel->rd_rules;		if (rules == NULL)		{			heap_close(rel, NoLock);			continue;		}		locks = NIL;		for (i = 0; i < rules->numLocks; i++)		{			rule = rules->rules[i];			if (rule->event != CMD_SELECT)				continue;			if (rule->attrno > 0)			{				/* per-attr rule; do we need it? */				if (!attribute_used((Node *) parsetree, rt_index,									rule->attrno, 0))					continue;			}			locks = lappend(locks, rule);		}		/*		 * If we found any, apply them --- but first check for recursion!		 */		if (locks != NIL)		{			ListCell   *l;			if (list_member_oid(activeRIRs, RelationGetRelid(rel)))				ereport(ERROR,						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),						 errmsg("infinite recursion detected in rules for relation \"%s\"",								RelationGetRelationName(rel))));			activeRIRs = lcons_oid(RelationGetRelid(rel), activeRIRs);			foreach(l, locks)			{				rule = lfirst(l);				parsetree = ApplyRetrieveRule(parsetree,											  rule,											  rt_index,											  rule->attrno == -1,											  rel,											  activeRIRs);			}			activeRIRs = list_delete_first(activeRIRs);		}		heap_close(rel, NoLock);	}	/*	 * Recurse into sublink subqueries, too.  But we already did the ones in	 * the rtable.	 */	if (parsetree->hasSubLinks)		query_tree_walker(parsetree, fireRIRonSubLink, (void *) activeRIRs,						  QTW_IGNORE_RT_SUBQUERIES);	return parsetree;}/* * Modify the given query by adding 'AND rule_qual IS NOT TRUE' to its * qualification.  This is used to generate suitable "else clauses" for * conditional INSTEAD rules.  (Unfortunately we must use "x IS NOT TRUE", * not just "NOT x" which the planner is much smarter about, else we will * do the wrong thing when the qual evaluates to NULL.) * * The rule_qual may contain references to OLD or NEW.	OLD references are * replaced by references to the specified rt_index (the relation that the * rule applies to).  NEW references are only possible for INSERT and UPDATE * queries on the relation itself, and so they should be replaced by copies * of the related entries in the query's own targetlist. */static Query *CopyAndAddInvertedQual(Query *parsetree,					   Node *rule_qual,					   int rt_index,					   CmdType event)

⌨️ 快捷键说明

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