版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
/*
* window_gettupleslot
* Fetch the pos'th tuple of the current partition into the slot,
* using the winobj's read pointer
*
* Returns true if successful, false if no such row
*/
static bool
window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
{
WindowAggState *winstate = winobj->winstate;
MemoryContext oldcontext;
/* often called repeatedly in a row */
CHECK_FOR_INTERRUPTS();
/* Don't allow passing -1 to spool_tuples here */
if (pos < 0)
return false;
/* If necessary, fetch the tuple into the spool */
spool_tuples(winstate, pos);
if (pos >= winstate->spooled_rows)
return false;
if (pos < winobj->markpos)
elog(ERROR, "cannot fetch row before WindowObject's mark position");
oldcontext = MemoryContextSwitchTo(winstate->ss.ps.ps_ExprContext->ecxt_per_query_memory);
tuplestore_select_read_pointer(winstate->buffer, winobj->readptr);
/*
* Advance or rewind until we are within one tuple of the one we want.
*/
if (winobj->seekpos < pos - 1)
{
if (!tuplestore_skiptuples(winstate->buffer,
pos - 1 - winobj->seekpos,
true))
elog(ERROR, "unexpected end of tuplestore");
winobj->seekpos = pos - 1;
}
else if (winobj->seekpos > pos + 1)
{
if (!tuplestore_skiptuples(winstate->buffer,
winobj->seekpos - (pos + 1),
false))
elog(ERROR, "unexpected end of tuplestore");
winobj->seekpos = pos + 1;
}
else if (winobj->seekpos == pos)
{
/*
* There's no API to refetch the tuple at the current position. We
* have to move one tuple forward, and then one backward. (We don't
* do it the other way because we might try to fetch the row before
* our mark, which isn't allowed.) XXX this case could stand to be
* optimized.
*/
tuplestore_advance(winstate->buffer, true);
winobj->seekpos++;
}
/*
* Now we should be on the tuple immediately before or after the one we
* want, so just fetch forwards or backwards as appropriate.
*/
if (winobj->seekpos > pos)
{
if (!tuplestore_gettupleslot(winstate->buffer, false, true, slot))
elog(ERROR, "unexpected end of tuplestore");
winobj->seekpos--;
}
else
{
if (!tuplestore_gettupleslot(winstate->buffer, true, true, slot))
elog(ERROR, "unexpected end of tuplestore");
winobj->seekpos++;
}
Assert(winobj->seekpos == pos);
MemoryContextSwitchTo(oldcontext);
return true;
}