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

📄 nodehashjoin.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * nodeHashjoin.c *	  Routines to handle hash join nodes * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.57.2.2 2004/09/17 18:29:10 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "executor/executor.h"#include "executor/nodeHash.h"#include "executor/nodeHashjoin.h"#include "optimizer/clauses.h"#include "utils/memutils.h"static TupleTableSlot *ExecHashJoinOuterGetTuple(PlanState *node,						  HashJoinState *hjstate);static TupleTableSlot *ExecHashJoinGetSavedTuple(HashJoinState *hjstate,						  BufFile *file,						  TupleTableSlot *tupleSlot);static int	ExecHashJoinNewBatch(HashJoinState *hjstate);/* ---------------------------------------------------------------- *		ExecHashJoin * *		This function implements the Hybrid Hashjoin algorithm. *		recursive partitioning remains to be added. *		Note: the relation we build hash table on is the inner *			  the other one is outer. * ---------------------------------------------------------------- */TupleTableSlot *				/* return: a tuple or NULL */ExecHashJoin(HashJoinState *node){	EState	   *estate;	PlanState  *outerNode;	HashState  *hashNode;	List	   *hjclauses;	List	   *outerkeys;	List	   *joinqual;	List	   *otherqual;	ScanDirection dir;	TupleTableSlot *inntuple;	ExprContext *econtext;	ExprDoneCond isDone;	HashJoinTable hashtable;	HeapTuple	curtuple;	TupleTableSlot *outerTupleSlot;	int			i;	/*	 * get information from HashJoin node	 */	hjclauses = node->hashclauses;	estate = node->js.ps.state;	joinqual = node->js.joinqual;	otherqual = node->js.ps.qual;	hashNode = (HashState *) innerPlanState(node);	outerNode = outerPlanState(node);	dir = estate->es_direction;	/*	 * get information from HashJoin state	 */	hashtable = node->hj_HashTable;	outerkeys = node->hj_OuterHashKeys;	econtext = node->js.ps.ps_ExprContext;	/*	 * Check to see if we're still projecting out tuples from a previous	 * join tuple (because there is a function-returning-set in the	 * projection expressions).  If so, try to project another one.	 */	if (node->js.ps.ps_TupFromTlist)	{		TupleTableSlot *result;		result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);		if (isDone == ExprMultipleResult)			return result;		/* Done with that source tuple... */		node->js.ps.ps_TupFromTlist = false;	}	/*	 * If we're doing an IN join, we want to return at most one row per	 * outer tuple; so we can stop scanning the inner scan if we matched	 * on the previous try.	 */	if (node->js.jointype == JOIN_IN &&		node->hj_MatchedOuter)		node->hj_NeedNewOuter = true;	/*	 * Reset per-tuple memory context to free any expression evaluation	 * storage allocated in the previous tuple cycle.  Note this can't	 * happen until we're done projecting out tuples from a join tuple.	 */	ResetExprContext(econtext);	/*	 * if this is the first call, build the hash table for inner relation	 */	if (!node->hj_hashdone)	{		/*		 * create the hash table		 */		Assert(hashtable == NULL);		hashtable = ExecHashTableCreate((Hash *) hashNode->ps.plan,										node->hj_HashOperators);		node->hj_HashTable = hashtable;		/*		 * execute the Hash node, to build the hash table		 */		hashNode->hashtable = hashtable;		(void) ExecProcNode((PlanState *) hashNode);		/*		 * Open temp files for outer batches, if needed. Note that file		 * buffers are palloc'd in regular executor context.		 */		for (i = 0; i < hashtable->nbatch; i++)			hashtable->outerBatchFile[i] = BufFileCreateTemp(false);		node->hj_hashdone = true;	}	/*	 * Now get an outer tuple and probe into the hash table for matches	 */	outerTupleSlot = node->js.ps.ps_OuterTupleSlot;	for (;;)	{		/*		 * If we don't have an outer tuple, get the next one		 */		if (node->hj_NeedNewOuter)		{			outerTupleSlot = ExecHashJoinOuterGetTuple(outerNode,													   node);			if (TupIsNull(outerTupleSlot))			{				/* end of join */				return NULL;			}			node->js.ps.ps_OuterTupleSlot = outerTupleSlot;			econtext->ecxt_outertuple = outerTupleSlot;			node->hj_NeedNewOuter = false;			node->hj_MatchedOuter = false;			/*			 * now we have an outer tuple, find the corresponding bucket			 * for this tuple from the hash table			 */			node->hj_CurBucketNo = ExecHashGetBucket(hashtable, econtext,													 outerkeys);			node->hj_CurTuple = NULL;			/*			 * Now we've got an outer tuple and the corresponding hash			 * bucket, but this tuple may not belong to the current batch.			 * This need only be checked in the first pass.			 */			if (hashtable->curbatch == 0)			{				int			batchno = ExecHashGetBatch(node->hj_CurBucketNo,													   hashtable);				if (batchno >= 0)				{					/*					 * Need to postpone this outer tuple to a later batch.					 * Save it in the corresponding outer-batch file.					 */					hashtable->outerBatchSize[batchno]++;					ExecHashJoinSaveTuple(outerTupleSlot->val,									 hashtable->outerBatchFile[batchno]);					node->hj_NeedNewOuter = true;					continue;	/* loop around for a new outer tuple */				}			}		}		/*		 * OK, scan the selected hash bucket for matches		 */		for (;;)		{			curtuple = ExecScanHashBucket(node,										  hjclauses,										  econtext);			if (curtuple == NULL)				break;			/* out of matches */			/*			 * we've got a match, but still need to test non-hashed quals			 */			inntuple = ExecStoreTuple(curtuple,									  node->hj_HashTupleSlot,									  InvalidBuffer,									  false);	/* don't pfree this tuple */			econtext->ecxt_innertuple = inntuple;			/* reset temp memory each time to avoid leaks from qual expr */			ResetExprContext(econtext);			/*			 * if we pass the qual, then save state for next call and have			 * ExecProject form the projection, store it in the tuple			 * table, and return the slot.			 *			 * Only the joinquals determine MatchedOuter status, but all			 * quals must pass to actually return the tuple.			 */			if (ExecQual(joinqual, econtext, false))			{				node->hj_MatchedOuter = true;				if (otherqual == NIL || ExecQual(otherqual, econtext, false))				{					TupleTableSlot *result;					result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);					if (isDone != ExprEndResult)					{						node->js.ps.ps_TupFromTlist =							(isDone == ExprMultipleResult);						return result;					}				}				/*				 * If we didn't return a tuple, may need to set				 * NeedNewOuter				 */				if (node->js.jointype == JOIN_IN)				{					node->hj_NeedNewOuter = true;					break;		/* out of loop over hash bucket */				}			}		}		/*		 * Now the current outer tuple has run out of matches, so check		 * whether to emit a dummy outer-join tuple. If not, loop around		 * to get a new outer tuple.		 */		node->hj_NeedNewOuter = true;		if (!node->hj_MatchedOuter &&			node->js.jointype == JOIN_LEFT)		{			/*			 * We are doing an outer join and there were no join matches			 * for this outer tuple.  Generate a fake join tuple with			 * nulls for the inner tuple, and return it if it passes the			 * non-join quals.			 */			econtext->ecxt_innertuple = node->hj_NullInnerTupleSlot;			if (ExecQual(otherqual, econtext, false))			{				/*				 * qualification was satisfied so we project and return				 * the slot containing the result tuple using				 * ExecProject().				 */				TupleTableSlot *result;				result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);				if (isDone != ExprEndResult)				{					node->js.ps.ps_TupFromTlist =						(isDone == ExprMultipleResult);					return result;				}			}		}	}}/* ---------------------------------------------------------------- *		ExecInitHashJoin * *		Init routine for HashJoin node. * ---------------------------------------------------------------- */HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate){	HashJoinState *hjstate;	Plan	   *outerNode;	Hash	   *hashNode;	List	   *hclauses;	List	   *hoperators;	List	   *hcl;	/*	 * create state structure	 */	hjstate = makeNode(HashJoinState);	hjstate->js.ps.plan = (Plan *) node;	hjstate->js.ps.state = estate;	/*	 * Miscellaneous initialization	 *	 * create expression context for node	 */	ExecAssignExprContext(estate, &hjstate->js.ps);	/*	 * initialize child expressions	 */	hjstate->js.ps.targetlist = (List *)		ExecInitExpr((Expr *) node->join.plan.targetlist,					 (PlanState *) hjstate);	hjstate->js.ps.qual = (List *)		ExecInitExpr((Expr *) node->join.plan.qual,					 (PlanState *) hjstate);	hjstate->js.jointype = node->join.jointype;	hjstate->js.joinqual = (List *)		ExecInitExpr((Expr *) node->join.joinqual,					 (PlanState *) hjstate);	hjstate->hashclauses = (List *)		ExecInitExpr((Expr *) node->hashclauses,					 (PlanState *) hjstate);	/*	 * initialize child nodes	 */	outerNode = outerPlan(node);	hashNode = (Hash *) innerPlan(node);	outerPlanState(hjstate) = ExecInitNode(outerNode, estate);	innerPlanState(hjstate) = ExecInitNode((Plan *) hashNode, estate);#define HASHJOIN_NSLOTS 3	/*	 * tuple table initialization	 */	ExecInitResultTupleSlot(estate, &hjstate->js.ps);	hjstate->hj_OuterTupleSlot = ExecInitExtraTupleSlot(estate);	switch (node->join.jointype)	{		case JOIN_INNER:		case JOIN_IN:			break;		case JOIN_LEFT:			hjstate->hj_NullInnerTupleSlot =				ExecInitNullTupleSlot(estate,							 ExecGetResultType(innerPlanState(hjstate)));			break;		default:			elog(ERROR, "unrecognized join type: %d",				 (int) node->join.jointype);	}

⌨️ 快捷键说明

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