mirror of
https://github.com/postgres/postgres.git
synced 2025-05-25 00:04:05 -04:00
New nodeGroup.c code uses own copy of first tuple in a group.
Free memory after comparison in nodeUnique.c
This commit is contained in:
parent
3d18ca70a7
commit
b1b246ab40
@ -13,7 +13,7 @@
|
|||||||
* columns. (ie. tuples from the same group are consecutive)
|
* columns. (ie. tuples from the same group are consecutive)
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.16 1998/02/10 16:02:58 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.17 1998/02/18 12:40:43 vadim Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -31,7 +31,7 @@
|
|||||||
static TupleTableSlot *ExecGroupEveryTuple(Group *node);
|
static TupleTableSlot *ExecGroupEveryTuple(Group *node);
|
||||||
static TupleTableSlot *ExecGroupOneTuple(Group *node);
|
static TupleTableSlot *ExecGroupOneTuple(Group *node);
|
||||||
static bool
|
static bool
|
||||||
sameGroup(TupleTableSlot *oldslot, TupleTableSlot *newslot,
|
sameGroup(HeapTuple oldslot, HeapTuple newslot,
|
||||||
int numCols, AttrNumber *grpColIdx, TupleDesc tupdesc);
|
int numCols, AttrNumber *grpColIdx, TupleDesc tupdesc);
|
||||||
|
|
||||||
/* ---------------------------------------
|
/* ---------------------------------------
|
||||||
@ -71,8 +71,8 @@ ExecGroupEveryTuple(Group *node)
|
|||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
|
|
||||||
HeapTuple outerTuple = NULL;
|
HeapTuple outerTuple = NULL;
|
||||||
TupleTableSlot *outerslot,
|
HeapTuple firsttuple;
|
||||||
*lastslot;
|
TupleTableSlot *outerslot;
|
||||||
ProjectionInfo *projInfo;
|
ProjectionInfo *projInfo;
|
||||||
TupleTableSlot *resultSlot;
|
TupleTableSlot *resultSlot;
|
||||||
|
|
||||||
@ -90,18 +90,14 @@ ExecGroupEveryTuple(Group *node)
|
|||||||
|
|
||||||
econtext = grpstate->csstate.cstate.cs_ExprContext;
|
econtext = grpstate->csstate.cstate.cs_ExprContext;
|
||||||
|
|
||||||
if (grpstate->grp_useLastTuple)
|
/* if we haven't returned first tuple of new group yet ... */
|
||||||
|
if (grpstate->grp_useFirstTuple)
|
||||||
{
|
{
|
||||||
|
grpstate->grp_useFirstTuple = FALSE;
|
||||||
|
|
||||||
/*
|
ExecStoreTuple(grpstate->grp_firstTuple,
|
||||||
* we haven't returned last tuple yet because it is not of the
|
|
||||||
* same group
|
|
||||||
*/
|
|
||||||
grpstate->grp_useLastTuple = FALSE;
|
|
||||||
|
|
||||||
ExecStoreTuple(grpstate->grp_lastSlot->val,
|
|
||||||
grpstate->csstate.css_ScanTupleSlot,
|
grpstate->csstate.css_ScanTupleSlot,
|
||||||
grpstate->grp_lastSlot->ttc_buffer,
|
InvalidBuffer,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -115,29 +111,28 @@ ExecGroupEveryTuple(Group *node)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
firsttuple = grpstate->grp_firstTuple;
|
||||||
* Compare with last tuple and see if this tuple is of
|
/* this should occur on the first call only */
|
||||||
* the same group.
|
if (firsttuple == NULL)
|
||||||
* ----------------
|
{
|
||||||
*/
|
grpstate->grp_firstTuple = heap_copytuple (outerTuple);
|
||||||
lastslot = grpstate->csstate.css_ScanTupleSlot;
|
}
|
||||||
|
else
|
||||||
if (lastslot->val != NULL &&
|
|
||||||
(!sameGroup(lastslot, outerslot,
|
|
||||||
node->numCols, node->grpColIdx,
|
|
||||||
ExecGetScanType(&grpstate->csstate))))
|
|
||||||
{
|
{
|
||||||
/* ExecGetResultType(&grpstate->csstate.cstate)))) {*/
|
|
||||||
|
|
||||||
grpstate->grp_useLastTuple = TRUE;
|
|
||||||
|
|
||||||
/* save it for next time */
|
|
||||||
grpstate->grp_lastSlot = outerslot;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* signifies the end of the group
|
* Compare with first tuple and see if this tuple is of
|
||||||
|
* the same group.
|
||||||
*/
|
*/
|
||||||
return NULL;
|
if (!sameGroup(firsttuple, outerslot->val,
|
||||||
|
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,
|
ExecStoreTuple(outerTuple,
|
||||||
@ -172,8 +167,8 @@ ExecGroupOneTuple(Group *node)
|
|||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
|
|
||||||
HeapTuple outerTuple = NULL;
|
HeapTuple outerTuple = NULL;
|
||||||
TupleTableSlot *outerslot,
|
HeapTuple firsttuple;
|
||||||
*lastslot;
|
TupleTableSlot *outerslot;
|
||||||
ProjectionInfo *projInfo;
|
ProjectionInfo *projInfo;
|
||||||
TupleTableSlot *resultSlot;
|
TupleTableSlot *resultSlot;
|
||||||
|
|
||||||
@ -191,15 +186,9 @@ ExecGroupOneTuple(Group *node)
|
|||||||
|
|
||||||
econtext = node->grpstate->csstate.cstate.cs_ExprContext;
|
econtext = node->grpstate->csstate.cstate.cs_ExprContext;
|
||||||
|
|
||||||
if (grpstate->grp_useLastTuple)
|
firsttuple = grpstate->grp_firstTuple;
|
||||||
{
|
/* this should occur on the first call only */
|
||||||
grpstate->grp_useLastTuple = FALSE;
|
if (firsttuple == NULL)
|
||||||
ExecStoreTuple(grpstate->grp_lastSlot->val,
|
|
||||||
grpstate->csstate.css_ScanTupleSlot,
|
|
||||||
grpstate->grp_lastSlot->ttc_buffer,
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
|
outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
|
||||||
if (outerslot)
|
if (outerslot)
|
||||||
@ -209,12 +198,8 @@ ExecGroupOneTuple(Group *node)
|
|||||||
grpstate->grp_done = TRUE;
|
grpstate->grp_done = TRUE;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ExecStoreTuple(outerTuple,
|
grpstate->grp_firstTuple = firsttuple = heap_copytuple (outerTuple);
|
||||||
grpstate->csstate.css_ScanTupleSlot,
|
|
||||||
outerslot->ttc_buffer,
|
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
lastslot = grpstate->csstate.css_ScanTupleSlot;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find all tuples that belong to a group
|
* find all tuples that belong to a group
|
||||||
@ -225,49 +210,21 @@ ExecGroupOneTuple(Group *node)
|
|||||||
outerTuple = (outerslot) ? outerslot->val : NULL;
|
outerTuple = (outerslot) ? outerslot->val : NULL;
|
||||||
if (!HeapTupleIsValid(outerTuple))
|
if (!HeapTupleIsValid(outerTuple))
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
|
||||||
* we have at least one tuple (lastslot) if we reach here
|
|
||||||
*/
|
|
||||||
grpstate->grp_done = TRUE;
|
grpstate->grp_done = TRUE;
|
||||||
|
|
||||||
/* return lastslot */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* Compare with last tuple and see if this tuple is of
|
* Compare with first tuple and see if this tuple is of
|
||||||
* the same group.
|
* the same group.
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if ((!sameGroup(lastslot, outerslot,
|
if ((!sameGroup(firsttuple, outerslot->val,
|
||||||
node->numCols, node->grpColIdx,
|
node->numCols, node->grpColIdx,
|
||||||
ExecGetScanType(&grpstate->csstate))))
|
ExecGetScanType(&grpstate->csstate))))
|
||||||
{
|
|
||||||
/* ExecGetResultType(&grpstate->csstate.cstate)))) {*/
|
|
||||||
|
|
||||||
grpstate->grp_useLastTuple = TRUE;
|
|
||||||
|
|
||||||
/* save it for next time */
|
|
||||||
grpstate->grp_lastSlot = outerslot;
|
|
||||||
|
|
||||||
/* return lastslot */
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
ExecStoreTuple(outerTuple,
|
|
||||||
grpstate->csstate.css_ScanTupleSlot,
|
|
||||||
outerslot->ttc_buffer,
|
|
||||||
false);
|
|
||||||
|
|
||||||
lastslot = grpstate->csstate.css_ScanTupleSlot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecStoreTuple(lastslot->val,
|
|
||||||
grpstate->csstate.css_ScanTupleSlot,
|
|
||||||
lastslot->ttc_buffer,
|
|
||||||
false);
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* form a projection tuple, store it in the result tuple
|
* form a projection tuple, store it in the result tuple
|
||||||
* slot and return it.
|
* slot and return it.
|
||||||
@ -275,8 +232,19 @@ ExecGroupOneTuple(Group *node)
|
|||||||
*/
|
*/
|
||||||
projInfo = grpstate->csstate.cstate.cs_ProjInfo;
|
projInfo = grpstate->csstate.cstate.cs_ProjInfo;
|
||||||
|
|
||||||
econtext->ecxt_scantuple = lastslot;
|
ExecStoreTuple(firsttuple,
|
||||||
|
grpstate->csstate.css_ScanTupleSlot,
|
||||||
|
InvalidBuffer,
|
||||||
|
false);
|
||||||
|
econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;
|
||||||
resultSlot = ExecProject(projInfo, &isDone);
|
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;
|
return resultSlot;
|
||||||
}
|
}
|
||||||
@ -304,7 +272,7 @@ ExecInitGroup(Group *node, EState *estate, Plan *parent)
|
|||||||
*/
|
*/
|
||||||
grpstate = makeNode(GroupState);
|
grpstate = makeNode(GroupState);
|
||||||
node->grpstate = grpstate;
|
node->grpstate = grpstate;
|
||||||
grpstate->grp_useLastTuple = FALSE;
|
grpstate->grp_useFirstTuple = FALSE;
|
||||||
grpstate->grp_done = FALSE;
|
grpstate->grp_done = FALSE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -370,6 +338,11 @@ ExecEndGroup(Group *node)
|
|||||||
|
|
||||||
/* clean up tuple table */
|
/* clean up tuple table */
|
||||||
ExecClearTuple(grpstate->csstate.css_ScanTupleSlot);
|
ExecClearTuple(grpstate->csstate.css_ScanTupleSlot);
|
||||||
|
if (grpstate->grp_firstTuple != NULL)
|
||||||
|
{
|
||||||
|
pfree (grpstate->grp_firstTuple);
|
||||||
|
grpstate->grp_firstTuple = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
@ -380,8 +353,8 @@ ExecEndGroup(Group *node)
|
|||||||
* code swiped from nodeUnique.c
|
* code swiped from nodeUnique.c
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
sameGroup(TupleTableSlot *oldslot,
|
sameGroup(HeapTuple oldtuple,
|
||||||
TupleTableSlot *newslot,
|
HeapTuple newtuple,
|
||||||
int numCols,
|
int numCols,
|
||||||
AttrNumber *grpColIdx,
|
AttrNumber *grpColIdx,
|
||||||
TupleDesc tupdesc)
|
TupleDesc tupdesc)
|
||||||
@ -401,12 +374,12 @@ sameGroup(TupleTableSlot *oldslot,
|
|||||||
att = grpColIdx[i];
|
att = grpColIdx[i];
|
||||||
typoutput = typtoout((Oid) tupdesc->attrs[att - 1]->atttypid);
|
typoutput = typtoout((Oid) tupdesc->attrs[att - 1]->atttypid);
|
||||||
|
|
||||||
attr1 = heap_getattr(oldslot->val,
|
attr1 = heap_getattr(oldtuple,
|
||||||
att,
|
att,
|
||||||
tupdesc,
|
tupdesc,
|
||||||
&isNull1);
|
&isNull1);
|
||||||
|
|
||||||
attr2 = heap_getattr(newslot->val,
|
attr2 = heap_getattr(newtuple,
|
||||||
att,
|
att,
|
||||||
tupdesc,
|
tupdesc,
|
||||||
&isNull2);
|
&isNull2);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.14 1998/02/10 16:03:03 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.15 1998/02/18 12:40:44 vadim Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -208,9 +208,14 @@ ExecUnique(Unique *node)
|
|||||||
* use strcmp for comparison
|
* use strcmp for comparison
|
||||||
*/
|
*/
|
||||||
if (strcmp(val1, val2) == 0) /* they are equal */
|
if (strcmp(val1, val2) == 0) /* they are equal */
|
||||||
|
{
|
||||||
|
pfree (val1);
|
||||||
|
pfree (val2);
|
||||||
continue;
|
continue;
|
||||||
else
|
}
|
||||||
break;
|
pfree (val1);
|
||||||
|
pfree (val2);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* one is null and the other isn't, they aren't equal */
|
/* one is null and the other isn't, they aren't equal */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user