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

📄 nodegroup.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
字号:
/*------------------------------------------------------------------------- * * nodeGroup.c *	  Routines to handle group nodes (used for queries with GROUP BY clause). * * Copyright (c) 1994, Regents of the University of California * * * DESCRIPTION *	  The Group node is designed for handling queries with a GROUP BY clause. *	  It's outer plan must be a sort node. It assumes that the tuples it gets *	  back from the outer plan is sorted in the order specified by the group *	  columns. (ie. tuples from the same group are consecutive) * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.27 1999/07/11 01:57:32 tgl Exp $ * *------------------------------------------------------------------------- */#include <string.h>#include "postgres.h"#include "fmgr.h"#include "access/heapam.h"#include "catalog/catalog.h"#include "access/printtup.h"#include "executor/executor.h"#include "executor/nodeGroup.h"static TupleTableSlot *ExecGroupEveryTuple(Group *node);static TupleTableSlot *ExecGroupOneTuple(Group *node);static bool sameGroup(HeapTuple oldslot, HeapTuple newslot,		  int numCols, AttrNumber *grpColIdx, TupleDesc tupdesc);/* --------------------------------------- *	 ExecGroup - * *		There are two modes in which tuples are returned by ExecGroup. If *		tuplePerGroup is TRUE, every tuple from the same group will be *		returned, followed by a NULL at the end of each group. This is *		useful for Agg node which needs to aggregate over tuples of the same *		group. (eg. SELECT salary, count{*} FROM emp GROUP BY salary) * *		If tuplePerGroup is FALSE, only one tuple per group is returned. The *		tuple returned contains only the group columns. NULL is returned only *		at the end when no more groups is present. This is useful when *		the query does not involve aggregates. (eg. SELECT salary FROM emp *		GROUP BY salary) * ------------------------------------------ */TupleTableSlot *ExecGroup(Group *node){	if (node->tuplePerGroup)		return ExecGroupEveryTuple(node);	else		return ExecGroupOneTuple(node);}/* * ExecGroupEveryTuple - *	 return every tuple with a NULL between each group */static TupleTableSlot *ExecGroupEveryTuple(Group *node){	GroupState *grpstate;	EState	   *estate;	ExprContext *econtext;	HeapTuple	outerTuple = NULL;	HeapTuple	firsttuple;	TupleTableSlot *outerslot;	ProjectionInfo *projInfo;	TupleTableSlot *resultSlot;	bool		isDone;	/* ---------------------	 *	get state info from node	 * ---------------------	 */	grpstate = node->grpstate;	if (grpstate->grp_done)		return NULL;	estate = node->plan.state;	econtext = grpstate->csstate.cstate.cs_ExprContext;	/* if we haven't returned first tuple of new group yet ... */	if (grpstate->grp_useFirstTuple)	{		grpstate->grp_useFirstTuple = FALSE;		ExecStoreTuple(grpstate->grp_firstTuple,					   grpstate->csstate.css_ScanTupleSlot,					   InvalidBuffer,					   false);	}	else	{		outerslot = ExecProcNode(outerPlan(node), (Plan *) node);		if (TupIsNull(outerslot))		{			grpstate->grp_done = TRUE;			return NULL;		}		outerTuple = outerslot->val;		firsttuple = grpstate->grp_firstTuple;		/* this should occur on the first call only */		if (firsttuple == NULL)			grpstate->grp_firstTuple = heap_copytuple(outerTuple);		else		{			/*			 * Compare with first tuple and see if this tuple is of the			 * same group.			 */			if (!sameGroup(firsttuple, outerTuple,						   node->numCols, node->grpColIdx,						   ExecGetScanType(&grpstate->csstate)))			{				grpstate->grp_useFirstTuple = TRUE;				pfree(firsttuple);				grpstate->grp_firstTuple = heap_copytuple(outerTuple);				return NULL;	/* signifies the end of the group */			}		}		ExecStoreTuple(outerTuple,					   grpstate->csstate.css_ScanTupleSlot,					   outerslot->ttc_buffer,					   false);	}	/* ----------------	 *	form a projection tuple, store it in the result tuple	 *	slot and return it.	 * ----------------	 */	projInfo = grpstate->csstate.cstate.cs_ProjInfo;	econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;	resultSlot = ExecProject(projInfo, &isDone);	return resultSlot;}/* * ExecGroupOneTuple - *	  returns one tuple per group, a NULL at the end when there are no more *	  tuples. */static TupleTableSlot *ExecGroupOneTuple(Group *node){	GroupState *grpstate;	EState	   *estate;	ExprContext *econtext;	HeapTuple	outerTuple = NULL;	HeapTuple	firsttuple;	TupleTableSlot *outerslot;	ProjectionInfo *projInfo;	TupleTableSlot *resultSlot;	bool		isDone;	/* ---------------------	 *	get state info from node	 * ---------------------	 */	grpstate = node->grpstate;	if (grpstate->grp_done)		return NULL;	estate = node->plan.state;	econtext = node->grpstate->csstate.cstate.cs_ExprContext;	firsttuple = grpstate->grp_firstTuple;	/* this should occur on the first call only */	if (firsttuple == NULL)	{		outerslot = ExecProcNode(outerPlan(node), (Plan *) node);		if (TupIsNull(outerslot))		{			grpstate->grp_done = TRUE;			return NULL;		}		grpstate->grp_firstTuple = firsttuple =			heap_copytuple(outerslot->val);	}	/*	 * find all tuples that belong to a group	 */	for (;;)	{		outerslot = ExecProcNode(outerPlan(node), (Plan *) node);		if (TupIsNull(outerslot))		{			grpstate->grp_done = TRUE;			outerTuple = NULL;			break;		}		outerTuple = outerslot->val;		/* ----------------		 *	Compare with first tuple and see if this tuple is of		 *	the same group.		 * ----------------		 */		if ((!sameGroup(firsttuple, outerTuple,						node->numCols, node->grpColIdx,						ExecGetScanType(&grpstate->csstate))))			break;	}	/* ----------------	 *	form a projection tuple, store it in the result tuple	 *	slot and return it.	 * ----------------	 */	projInfo = grpstate->csstate.cstate.cs_ProjInfo;	ExecStoreTuple(firsttuple,				   grpstate->csstate.css_ScanTupleSlot,				   InvalidBuffer,				   false);	econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;	resultSlot = ExecProject(projInfo, &isDone);	/* save outerTuple if we are not done yet */	if (!grpstate->grp_done)	{		pfree(firsttuple);		grpstate->grp_firstTuple = heap_copytuple(outerTuple);	}	return resultSlot;}/* ----------------- * ExecInitGroup * *	Creates the run-time information for the group node produced by the *	planner and initializes its outer subtree * ----------------- */boolExecInitGroup(Group *node, EState *estate, Plan *parent){	GroupState *grpstate;	Plan	   *outerPlan;	/*	 * assign the node's execution state	 */	node->plan.state = estate;	/*	 * create state structure	 */	grpstate = makeNode(GroupState);	node->grpstate = grpstate;	grpstate->grp_useFirstTuple = FALSE;	grpstate->grp_done = FALSE;	grpstate->grp_firstTuple = NULL;	/*	 * assign node's base id and create expression context	 */	ExecAssignNodeBaseInfo(estate, &grpstate->csstate.cstate,						   (Plan *) parent);	ExecAssignExprContext(estate, &grpstate->csstate.cstate);#define GROUP_NSLOTS 2	/*	 * tuple table initialization	 */	ExecInitScanTupleSlot(estate, &grpstate->csstate);	ExecInitResultTupleSlot(estate, &grpstate->csstate.cstate);	/*	 * initializes child nodes	 */	outerPlan = outerPlan(node);	ExecInitNode(outerPlan, estate, (Plan *) node);	/* ----------------	 *	initialize tuple type.	 * ----------------	 */	ExecAssignScanTypeFromOuterPlan((Plan *) node, &grpstate->csstate);	/*	 * Initialize tuple type for both result and scan. This node does no	 * projection	 */	ExecAssignResultTypeFromTL((Plan *) node, &grpstate->csstate.cstate);	ExecAssignProjectionInfo((Plan *) node, &grpstate->csstate.cstate);	return TRUE;}intExecCountSlotsGroup(Group *node){	return ExecCountSlotsNode(outerPlan(node)) + GROUP_NSLOTS;}/* ------------------------ *		ExecEndGroup(node) * * ----------------------- */voidExecEndGroup(Group *node){	GroupState *grpstate;	Plan	   *outerPlan;	grpstate = node->grpstate;	ExecFreeProjectionInfo(&grpstate->csstate.cstate);	outerPlan = outerPlan(node);	ExecEndNode(outerPlan, (Plan *) node);	/* clean up tuple table */	ExecClearTuple(grpstate->csstate.css_ScanTupleSlot);	if (grpstate->grp_firstTuple != NULL)	{		pfree(grpstate->grp_firstTuple);		grpstate->grp_firstTuple = NULL;	}}/***************************************************************************** * *****************************************************************************//* * code swiped from nodeUnique.c */static boolsameGroup(HeapTuple oldtuple,		  HeapTuple newtuple,		  int numCols,		  AttrNumber *grpColIdx,		  TupleDesc tupdesc){	bool		isNull1,				isNull2;	Datum		attr1,				attr2;	char	   *val1,			   *val2;	int			i;	AttrNumber	att;	Oid			typoutput,				typelem;	for (i = 0; i < numCols; i++)	{		att = grpColIdx[i];		getTypeOutAndElem((Oid) tupdesc->attrs[att - 1]->atttypid,						  &typoutput, &typelem);		attr1 = heap_getattr(oldtuple,							 att,							 tupdesc,							 &isNull1);		attr2 = heap_getattr(newtuple,							 att,							 tupdesc,							 &isNull2);		if (isNull1 == isNull2)		{			if (isNull1)		/* both are null, they are equal */				continue;			val1 = fmgr(typoutput, attr1, typelem,						tupdesc->attrs[att - 1]->atttypmod);			val2 = fmgr(typoutput, attr2, typelem,						tupdesc->attrs[att - 1]->atttypmod);			/*			 * now, val1 and val2 are ascii representations so we can use			 * strcmp for comparison			 */			if (strcmp(val1, val2) != 0)			{				pfree(val1);				pfree(val2);				return FALSE;			}			pfree(val1);			pfree(val2);		}		else		{			/* one is null and the other isn't, they aren't equal */			return FALSE;		}	}	return TRUE;}voidExecReScanGroup(Group *node, ExprContext *exprCtxt, Plan *parent){	GroupState *grpstate = node->grpstate;	grpstate->grp_useFirstTuple = FALSE;	grpstate->grp_done = FALSE;	if (grpstate->grp_firstTuple != NULL)	{		pfree(grpstate->grp_firstTuple);		grpstate->grp_firstTuple = NULL;	}	if (((Plan *) node)->lefttree &&		((Plan *) node)->lefttree->chgParam == NULL)		ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);}

⌨️ 快捷键说明

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