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

📄 nodehashjoin.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 2 页
字号:
	/*	 * now for some voodoo.  our temporary tuple slot is actually the	 * result tuple slot of the Hash node (which is our inner plan).  we	 * do this because Hash nodes don't return tuples via ExecProcNode()	 * -- instead the hash join node uses ExecScanHashBucket() to get at	 * the contents of the hash table.	-cim 6/9/91	 */	{		HashState  *hashstate = (HashState *) innerPlanState(hjstate);		TupleTableSlot *slot = hashstate->ps.ps_ResultTupleSlot;		hjstate->hj_HashTupleSlot = slot;	}	/*	 * initialize tuple type and projection info	 */	ExecAssignResultTypeFromTL(&hjstate->js.ps);	ExecAssignProjectionInfo(&hjstate->js.ps);	ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot,						  ExecGetResultType(outerPlanState(hjstate)),						  false);	/*	 * initialize hash-specific info	 */	hjstate->hj_hashdone = false;	hjstate->hj_HashTable = (HashJoinTable) NULL;	hjstate->hj_CurBucketNo = 0;	hjstate->hj_CurTuple = (HashJoinTuple) NULL;	/*	 * The planner already made a list of the inner hashkeys for us, but	 * we also need a list of the outer hashkeys, as well as a list of the	 * hash operator OIDs.	Both lists of exprs must then be prepared for	 * execution.	 */	hjstate->hj_InnerHashKeys = (List *)		ExecInitExpr((Expr *) hashNode->hashkeys,					 (PlanState *) hjstate);	((HashState *) innerPlanState(hjstate))->hashkeys =		hjstate->hj_InnerHashKeys;	hclauses = NIL;	hoperators = NIL;	foreach(hcl, node->hashclauses)	{		OpExpr	   *hclause = (OpExpr *) lfirst(hcl);		Assert(IsA(hclause, OpExpr));		hclauses = lappend(hclauses, get_leftop((Expr *) hclause));		hoperators = lappendo(hoperators, hclause->opno);	}	hjstate->hj_OuterHashKeys = (List *)		ExecInitExpr((Expr *) hclauses,					 (PlanState *) hjstate);	hjstate->hj_HashOperators = hoperators;	hjstate->js.ps.ps_OuterTupleSlot = NULL;	hjstate->js.ps.ps_TupFromTlist = false;	hjstate->hj_NeedNewOuter = true;	hjstate->hj_MatchedOuter = false;	return hjstate;}intExecCountSlotsHashJoin(HashJoin *node){	return ExecCountSlotsNode(outerPlan(node)) +		ExecCountSlotsNode(innerPlan(node)) +		HASHJOIN_NSLOTS;}/* ---------------------------------------------------------------- *		ExecEndHashJoin * *		clean up routine for HashJoin node * ---------------------------------------------------------------- */voidExecEndHashJoin(HashJoinState *node){	/*	 * Free hash table	 */	if (node->hj_HashTable)	{		ExecHashTableDestroy(node->hj_HashTable);		node->hj_HashTable = NULL;	}	/*	 * Free the exprcontext	 */	ExecFreeExprContext(&node->js.ps);	/*	 * clean out the tuple table	 */	ExecClearTuple(node->js.ps.ps_ResultTupleSlot);	ExecClearTuple(node->hj_OuterTupleSlot);	ExecClearTuple(node->hj_HashTupleSlot);	/*	 * clean up subtrees	 */	ExecEndNode(outerPlanState(node));	ExecEndNode(innerPlanState(node));}/* ---------------------------------------------------------------- *		ExecHashJoinOuterGetTuple * *		get the next outer tuple for hashjoin: either by *		executing a plan node as in the first pass, or from *		the tmp files for the hashjoin batches. * ---------------------------------------------------------------- */static TupleTableSlot *ExecHashJoinOuterGetTuple(PlanState *node, HashJoinState *hjstate){	HashJoinTable hashtable = hjstate->hj_HashTable;	int			curbatch = hashtable->curbatch;	TupleTableSlot *slot;	if (curbatch == 0)	{							/* if it is the first pass */		slot = ExecProcNode(node);		if (!TupIsNull(slot))			return slot;		/*		 * We have just reached the end of the first pass. Try to switch		 * to a saved batch.		 */		curbatch = ExecHashJoinNewBatch(hjstate);	}	/*	 * Try to read from a temp file. Loop allows us to advance to new	 * batch as needed.	 */	while (curbatch <= hashtable->nbatch)	{		slot = ExecHashJoinGetSavedTuple(hjstate,								 hashtable->outerBatchFile[curbatch - 1],										 hjstate->hj_OuterTupleSlot);		if (!TupIsNull(slot))			return slot;		curbatch = ExecHashJoinNewBatch(hjstate);	}	/* Out of batches... */	return NULL;}/* ---------------------------------------------------------------- *		ExecHashJoinGetSavedTuple * *		read the next tuple from a tmp file * ---------------------------------------------------------------- */static TupleTableSlot *ExecHashJoinGetSavedTuple(HashJoinState *hjstate,						  BufFile *file,						  TupleTableSlot *tupleSlot){	HeapTupleData htup;	size_t		nread;	HeapTuple	heapTuple;	nread = BufFileRead(file, (void *) &htup, sizeof(HeapTupleData));	if (nread == 0)		return NULL;			/* end of file */	if (nread != sizeof(HeapTupleData))		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not read from hash-join temporary file: %m")));	heapTuple = palloc(HEAPTUPLESIZE + htup.t_len);	memcpy((char *) heapTuple, (char *) &htup, sizeof(HeapTupleData));	heapTuple->t_datamcxt = CurrentMemoryContext;	heapTuple->t_data = (HeapTupleHeader)		((char *) heapTuple + HEAPTUPLESIZE);	nread = BufFileRead(file, (void *) heapTuple->t_data, htup.t_len);	if (nread != (size_t) htup.t_len)		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not read from hash-join temporary file: %m")));	return ExecStoreTuple(heapTuple, tupleSlot, InvalidBuffer, true);}/* ---------------------------------------------------------------- *		ExecHashJoinNewBatch * *		switch to a new hashjoin batch * ---------------------------------------------------------------- */static intExecHashJoinNewBatch(HashJoinState *hjstate){	HashJoinTable hashtable = hjstate->hj_HashTable;	int			nbatch = hashtable->nbatch;	int			newbatch = hashtable->curbatch + 1;	long	   *innerBatchSize = hashtable->innerBatchSize;	long	   *outerBatchSize = hashtable->outerBatchSize;	BufFile    *innerFile;	TupleTableSlot *slot;	ExprContext *econtext;	List	   *innerhashkeys;	if (newbatch > 1)	{		/*		 * We no longer need the previous outer batch file; close it right		 * away to free disk space.		 */		BufFileClose(hashtable->outerBatchFile[newbatch - 2]);		hashtable->outerBatchFile[newbatch - 2] = NULL;	}	/*	 * Normally we can skip over any batches that are empty on either side	 * --- but for JOIN_LEFT, can only skip when left side is empty.	 * Release associated temp files right away.	 */	while (newbatch <= nbatch &&		   (outerBatchSize[newbatch - 1] == 0L ||			(innerBatchSize[newbatch - 1] == 0L &&			 hjstate->js.jointype != JOIN_LEFT)))	{		BufFileClose(hashtable->innerBatchFile[newbatch - 1]);		hashtable->innerBatchFile[newbatch - 1] = NULL;		BufFileClose(hashtable->outerBatchFile[newbatch - 1]);		hashtable->outerBatchFile[newbatch - 1] = NULL;		newbatch++;	}	if (newbatch > nbatch)		return newbatch;		/* no more batches */	/*	 * Rewind inner and outer batch files for this batch, so that we can	 * start reading them.	 */	if (BufFileSeek(hashtable->outerBatchFile[newbatch - 1], 0, 0L, SEEK_SET))		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not rewind hash-join temporary file: %m")));	innerFile = hashtable->innerBatchFile[newbatch - 1];	if (BufFileSeek(innerFile, 0, 0L, SEEK_SET))		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not rewind hash-join temporary file: %m")));	/*	 * Reload the hash table with the new inner batch	 */	ExecHashTableReset(hashtable, innerBatchSize[newbatch - 1]);	econtext = hjstate->js.ps.ps_ExprContext;	innerhashkeys = hjstate->hj_InnerHashKeys;	while ((slot = ExecHashJoinGetSavedTuple(hjstate,											 innerFile,											 hjstate->hj_HashTupleSlot))		   && !TupIsNull(slot))	{		econtext->ecxt_innertuple = slot;		ExecHashTableInsert(hashtable, econtext, innerhashkeys);	}	/*	 * after we build the hash table, the inner batch file is no longer	 * needed	 */	BufFileClose(innerFile);	hashtable->innerBatchFile[newbatch - 1] = NULL;	hashtable->curbatch = newbatch;	return newbatch;}/* ---------------------------------------------------------------- *		ExecHashJoinSaveTuple * *		save a tuple to a tmp file. * * The data recorded in the file for each tuple is an image of its * HeapTupleData (with meaningless t_data pointer) followed by the * HeapTupleHeader and tuple data. * ---------------------------------------------------------------- */voidExecHashJoinSaveTuple(HeapTuple heapTuple,					  BufFile *file){	size_t		written;	written = BufFileWrite(file, (void *) heapTuple, sizeof(HeapTupleData));	if (written != sizeof(HeapTupleData))		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not write to hash-join temporary file: %m")));	written = BufFileWrite(file, (void *) heapTuple->t_data, heapTuple->t_len);	if (written != (size_t) heapTuple->t_len)		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not write to hash-join temporary file: %m")));}voidExecReScanHashJoin(HashJoinState *node, ExprContext *exprCtxt){	/*	 * If we haven't yet built the hash table then we can just return;	 * nothing done yet, so nothing to undo.	 */	if (!node->hj_hashdone)		return;	Assert(node->hj_HashTable != NULL);	/*	 * In a multi-batch join, we currently have to do rescans the hard	 * way, primarily because batch temp files may have already been	 * released. But if it's a single-batch join, and there is no	 * parameter change for the inner subnode, then we can just re-use the	 * existing hash table without rebuilding it.	 */	if (node->hj_HashTable->nbatch == 0 &&		((PlanState *) node)->righttree->chgParam == NULL)	{		/* okay to reuse the hash table; needn't rescan inner, either */	}	else	{		/* must destroy and rebuild hash table */		node->hj_hashdone = false;		ExecHashTableDestroy(node->hj_HashTable);		node->hj_HashTable = NULL;		/*		 * if chgParam of subnode is not null then plan will be re-scanned		 * by first ExecProcNode.		 */		if (((PlanState *) node)->righttree->chgParam == NULL)			ExecReScan(((PlanState *) node)->righttree, exprCtxt);	}	/* Always reset intra-tuple state */	node->hj_CurBucketNo = 0;	node->hj_CurTuple = (HashJoinTuple) NULL;	node->js.ps.ps_OuterTupleSlot = (TupleTableSlot *) NULL;	node->js.ps.ps_TupFromTlist = false;	node->hj_NeedNewOuter = true;	node->hj_MatchedOuter = false;	/*	 * if chgParam of subnode is not null then plan will be re-scanned by	 * first ExecProcNode.	 */	if (((PlanState *) node)->lefttree->chgParam == NULL)		ExecReScan(((PlanState *) node)->lefttree, exprCtxt);}

⌨️ 快捷键说明

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