tidpath.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 259 行

C
259
字号
/*------------------------------------------------------------------------- * * tidpath.c *	  Routines to determine which TID conditions are usable for scanning *	  a given relation, and create TidPaths accordingly. * * What we are looking for here is WHERE conditions of the form * "CTID = pseudoconstant", which can be implemented by just fetching * the tuple directly via heap_fetch().  We can also handle OR'd conditions * such as (CTID = const1) OR (CTID = const2), as well as ScalarArrayOpExpr * conditions of the form CTID = ANY(pseudoconstant_array).  In particular * this allows *		WHERE ctid IN (tid1, tid2, ...) * * We also support "WHERE CURRENT OF cursor" conditions (CurrentOfExpr), * which amount to "CTID = run-time-determined-TID".  These could in * theory be translated to a simple comparison of CTID to the result of * a function, but in practice it works better to keep the special node * representation all the way through to execution. * * There is currently no special support for joins involving CTID; in * particular nothing corresponding to best_inner_indexscan().	Since it's * not very useful to store TIDs of one table in another table, there * doesn't seem to be enough use-case to justify adding a lot of code * for that. * * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/optimizer/path/tidpath.c,v 1.31 2008/01/01 19:45:50 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/htup.h"#include "catalog/pg_operator.h"#include "catalog/pg_type.h"#include "optimizer/clauses.h"#include "optimizer/pathnode.h"#include "optimizer/paths.h"#include "parser/parse_expr.h"static bool IsTidEqualClause(OpExpr *node, int varno);static bool IsTidEqualAnyClause(ScalarArrayOpExpr *node, int varno);static List *TidQualFromExpr(Node *expr, int varno);static List *TidQualFromRestrictinfo(List *restrictinfo, int varno);/* * Check to see if an opclause is of the form *		CTID = pseudoconstant * or *		pseudoconstant = CTID * * We check that the CTID Var belongs to relation "varno".	That is probably * redundant considering this is only applied to restriction clauses, but * let's be safe. */static boolIsTidEqualClause(OpExpr *node, int varno){	Node	   *arg1,			   *arg2,			   *other;	Var		   *var;	/* Operator must be tideq */	if (node->opno != TIDEqualOperator)		return false;	if (list_length(node->args) != 2)		return false;	arg1 = linitial(node->args);	arg2 = lsecond(node->args);	/* Look for CTID as either argument */	other = NULL;	if (arg1 && IsA(arg1, Var))	{		var = (Var *) arg1;		if (var->varattno == SelfItemPointerAttributeNumber &&			var->vartype == TIDOID &&			var->varno == varno &&			var->varlevelsup == 0)			other = arg2;	}	if (!other && arg2 && IsA(arg2, Var))	{		var = (Var *) arg2;		if (var->varattno == SelfItemPointerAttributeNumber &&			var->vartype == TIDOID &&			var->varno == varno &&			var->varlevelsup == 0)			other = arg1;	}	if (!other)		return false;	if (exprType(other) != TIDOID)		return false;			/* probably can't happen */	/* The other argument must be a pseudoconstant */	if (!is_pseudo_constant_clause(other))		return false;	return true;				/* success */}/* * Check to see if a clause is of the form *		CTID = ANY (pseudoconstant_array) */static boolIsTidEqualAnyClause(ScalarArrayOpExpr *node, int varno){	Node	   *arg1,			   *arg2;	/* Operator must be tideq */	if (node->opno != TIDEqualOperator)		return false;	if (!node->useOr)		return false;	Assert(list_length(node->args) == 2);	arg1 = linitial(node->args);	arg2 = lsecond(node->args);	/* CTID must be first argument */	if (arg1 && IsA(arg1, Var))	{		Var		   *var = (Var *) arg1;		if (var->varattno == SelfItemPointerAttributeNumber &&			var->vartype == TIDOID &&			var->varno == varno &&			var->varlevelsup == 0)		{			/* The other argument must be a pseudoconstant */			if (is_pseudo_constant_clause(arg2))				return true;	/* success */		}	}	return false;}/* *	Extract a set of CTID conditions from the given qual expression * *	Returns a List of CTID qual expressions (with implicit OR semantics *	across the list), or NIL if there are no usable conditions. * *	If the expression is an AND clause, we can use a CTID condition *	from any sub-clause.  If it is an OR clause, we must be able to *	extract a CTID condition from every sub-clause, or we can't use it. * *	In theory, in the AND case we could get CTID conditions from different *	sub-clauses, in which case we could try to pick the most efficient one. *	In practice, such usage seems very unlikely, so we don't bother; we *	just exit as soon as we find the first candidate. */static List *TidQualFromExpr(Node *expr, int varno){	List	   *rlst = NIL;	ListCell   *l;	if (is_opclause(expr))	{		/* base case: check for tideq opclause */		if (IsTidEqualClause((OpExpr *) expr, varno))			rlst = list_make1(expr);	}	else if (expr && IsA(expr, ScalarArrayOpExpr))	{		/* another base case: check for tid = ANY clause */		if (IsTidEqualAnyClause((ScalarArrayOpExpr *) expr, varno))			rlst = list_make1(expr);	}	else if (expr && IsA(expr, CurrentOfExpr))	{		/* another base case: check for CURRENT OF on this rel */		if (((CurrentOfExpr *) expr)->cvarno == varno)			rlst = list_make1(expr);	}	else if (and_clause(expr))	{		foreach(l, ((BoolExpr *) expr)->args)		{			rlst = TidQualFromExpr((Node *) lfirst(l), varno);			if (rlst)				break;		}	}	else if (or_clause(expr))	{		foreach(l, ((BoolExpr *) expr)->args)		{			List	   *frtn = TidQualFromExpr((Node *) lfirst(l), varno);			if (frtn)				rlst = list_concat(rlst, frtn);			else			{				if (rlst)					list_free(rlst);				rlst = NIL;				break;			}		}	}	return rlst;}/* *	Extract a set of CTID conditions from the given restrictinfo list * *	This is essentially identical to the AND case of TidQualFromExpr, *	except for the format of the input. */static List *TidQualFromRestrictinfo(List *restrictinfo, int varno){	List	   *rlst = NIL;	ListCell   *l;	foreach(l, restrictinfo)	{		RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);		if (!IsA(rinfo, RestrictInfo))			continue;			/* probably should never happen */		rlst = TidQualFromExpr((Node *) rinfo->clause, varno);		if (rlst)			break;	}	return rlst;}/* * create_tidscan_paths *	  Create paths corresponding to direct TID scans of the given rel. * *	  Candidate paths are added to the rel's pathlist (using add_path). */voidcreate_tidscan_paths(PlannerInfo *root, RelOptInfo *rel){	List	   *tidquals;	tidquals = TidQualFromRestrictinfo(rel->baserestrictinfo, rel->relid);	if (tidquals)		add_path(rel, (Path *) create_tidscan_path(root, rel, tidquals));}

⌨️ 快捷键说明

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