PostgreSQL Source Code  git master
tuplestore.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/htup_details.h"
#include "commands/tablespace.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "storage/buffile.h"
#include "utils/memutils.h"
#include "utils/resowner.h"
Include dependency graph for tuplestore.c:

Go to the source code of this file.

Data Structures

struct  TSReadPointer
 
struct  Tuplestorestate
 

Macros

#define COPYTUP(state, tup)   ((*(state)->copytup) (state, tup))
 
#define WRITETUP(state, tup)   ((*(state)->writetup) (state, tup))
 
#define READTUP(state, len)   ((*(state)->readtup) (state, len))
 
#define LACKMEM(state)   ((state)->availMem < 0)
 
#define USEMEM(state, amt)   ((state)->availMem -= (amt))
 
#define FREEMEM(state, amt)   ((state)->availMem += (amt))
 

Enumerations

enum  TupStoreStatus { TSS_INMEM , TSS_WRITEFILE , TSS_READFILE }
 

Functions

static Tuplestorestatetuplestore_begin_common (int eflags, bool interXact, int maxKBytes)
 
static void tuplestore_puttuple_common (Tuplestorestate *state, void *tuple)
 
static void dumptuples (Tuplestorestate *state)
 
static unsigned int getlen (Tuplestorestate *state, bool eofOK)
 
static void * copytup_heap (Tuplestorestate *state, void *tup)
 
static void writetup_heap (Tuplestorestate *state, void *tup)
 
static void * readtup_heap (Tuplestorestate *state, unsigned int len)
 
Tuplestorestatetuplestore_begin_heap (bool randomAccess, bool interXact, int maxKBytes)
 
void tuplestore_set_eflags (Tuplestorestate *state, int eflags)
 
int tuplestore_alloc_read_pointer (Tuplestorestate *state, int eflags)
 
void tuplestore_clear (Tuplestorestate *state)
 
void tuplestore_end (Tuplestorestate *state)
 
void tuplestore_select_read_pointer (Tuplestorestate *state, int ptr)
 
int64 tuplestore_tuple_count (Tuplestorestate *state)
 
bool tuplestore_ateof (Tuplestorestate *state)
 
static bool grow_memtuples (Tuplestorestate *state)
 
void tuplestore_puttupleslot (Tuplestorestate *state, TupleTableSlot *slot)
 
void tuplestore_puttuple (Tuplestorestate *state, HeapTuple tuple)
 
void tuplestore_putvalues (Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
 
static void * tuplestore_gettuple (Tuplestorestate *state, bool forward, bool *should_free)
 
bool tuplestore_gettupleslot (Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
 
bool tuplestore_advance (Tuplestorestate *state, bool forward)
 
bool tuplestore_skiptuples (Tuplestorestate *state, int64 ntuples, bool forward)
 
void tuplestore_rescan (Tuplestorestate *state)
 
void tuplestore_copy_read_pointer (Tuplestorestate *state, int srcptr, int destptr)
 
void tuplestore_trim (Tuplestorestate *state)
 
bool tuplestore_in_memory (Tuplestorestate *state)
 

Macro Definition Documentation

◆ COPYTUP

#define COPYTUP (   state,
  tup 
)    ((*(state)->copytup) (state, tup))

Definition at line 183 of file tuplestore.c.

◆ FREEMEM

#define FREEMEM (   state,
  amt 
)    ((state)->availMem += (amt))

Definition at line 188 of file tuplestore.c.

◆ LACKMEM

#define LACKMEM (   state)    ((state)->availMem < 0)

Definition at line 186 of file tuplestore.c.

◆ READTUP

#define READTUP (   state,
  len 
)    ((*(state)->readtup) (state, len))

Definition at line 185 of file tuplestore.c.

◆ USEMEM

#define USEMEM (   state,
  amt 
)    ((state)->availMem -= (amt))

Definition at line 187 of file tuplestore.c.

◆ WRITETUP

#define WRITETUP (   state,
  tup 
)    ((*(state)->writetup) (state, tup))

Definition at line 184 of file tuplestore.c.

Enumeration Type Documentation

◆ TupStoreStatus

Enumerator
TSS_INMEM 
TSS_WRITEFILE 
TSS_READFILE 

Definition at line 72 of file tuplestore.c.

73 {
74  TSS_INMEM, /* Tuples still fit in memory */
75  TSS_WRITEFILE, /* Writing to temp file */
76  TSS_READFILE, /* Reading from temp file */
TupStoreStatus
Definition: tuplestore.c:73
@ TSS_READFILE
Definition: tuplestore.c:76
@ TSS_INMEM
Definition: tuplestore.c:74
@ TSS_WRITEFILE
Definition: tuplestore.c:75

Function Documentation

◆ copytup_heap()

static void * copytup_heap ( Tuplestorestate state,
void *  tup 
)
static

Definition at line 1490 of file tuplestore.c.

1491 {
1492  MinimalTuple tuple;
1493 
1495  USEMEM(state, GetMemoryChunkSpace(tuple));
1496  return (void *) tuple;
1497 }
MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup)
Definition: heaptuple.c:1576
Size GetMemoryChunkSpace(void *pointer)
Definition: mcxt.c:709
Definition: regguts.h:323
#define USEMEM(state, amt)
Definition: tuplestore.c:187

References GetMemoryChunkSpace(), minimal_tuple_from_heap_tuple(), and USEMEM.

Referenced by tuplestore_begin_heap().

◆ dumptuples()

static void dumptuples ( Tuplestorestate state)
static

Definition at line 1206 of file tuplestore.c.

1207 {
1208  int i;
1209 
1210  for (i = state->memtupdeleted;; i++)
1211  {
1212  TSReadPointer *readptr = state->readptrs;
1213  int j;
1214 
1215  for (j = 0; j < state->readptrcount; readptr++, j++)
1216  {
1217  if (i == readptr->current && !readptr->eof_reached)
1218  BufFileTell(state->myfile,
1219  &readptr->file, &readptr->offset);
1220  }
1221  if (i >= state->memtupcount)
1222  break;
1223  WRITETUP(state, state->memtuples[i]);
1224  }
1225  state->memtupdeleted = 0;
1226  state->memtupcount = 0;
1227 }
void BufFileTell(BufFile *file, int *fileno, off_t *offset)
Definition: buffile.c:833
int j
Definition: isn.c:74
int i
Definition: isn.c:73
bool eof_reached
Definition: tuplestore.c:94
off_t offset
Definition: tuplestore.c:97
#define WRITETUP(state, tup)
Definition: tuplestore.c:184

References BufFileTell(), TSReadPointer::current, TSReadPointer::eof_reached, TSReadPointer::file, i, j, TSReadPointer::offset, and WRITETUP.

Referenced by tuplestore_puttuple_common().

◆ getlen()

static unsigned int getlen ( Tuplestorestate state,
bool  eofOK 
)
static

Definition at line 1466 of file tuplestore.c.

1467 {
1468  unsigned int len;
1469  size_t nbytes;
1470 
1471  nbytes = BufFileReadMaybeEOF(state->myfile, &len, sizeof(len), eofOK);
1472  if (nbytes == 0)
1473  return 0;
1474  else
1475  return len;
1476 }
size_t BufFileReadMaybeEOF(BufFile *file, void *ptr, size_t size, bool eofOK)
Definition: buffile.c:664
const void size_t len

References BufFileReadMaybeEOF(), and len.

Referenced by tuplestore_gettuple().

◆ grow_memtuples()

static bool grow_memtuples ( Tuplestorestate state)
static

Definition at line 578 of file tuplestore.c.

579 {
580  int newmemtupsize;
581  int memtupsize = state->memtupsize;
582  int64 memNowUsed = state->allowedMem - state->availMem;
583 
584  /* Forget it if we've already maxed out memtuples, per comment above */
585  if (!state->growmemtuples)
586  return false;
587 
588  /* Select new value of memtupsize */
589  if (memNowUsed <= state->availMem)
590  {
591  /*
592  * We've used no more than half of allowedMem; double our usage,
593  * clamping at INT_MAX tuples.
594  */
595  if (memtupsize < INT_MAX / 2)
596  newmemtupsize = memtupsize * 2;
597  else
598  {
599  newmemtupsize = INT_MAX;
600  state->growmemtuples = false;
601  }
602  }
603  else
604  {
605  /*
606  * This will be the last increment of memtupsize. Abandon doubling
607  * strategy and instead increase as much as we safely can.
608  *
609  * To stay within allowedMem, we can't increase memtupsize by more
610  * than availMem / sizeof(void *) elements. In practice, we want to
611  * increase it by considerably less, because we need to leave some
612  * space for the tuples to which the new array slots will refer. We
613  * assume the new tuples will be about the same size as the tuples
614  * we've already seen, and thus we can extrapolate from the space
615  * consumption so far to estimate an appropriate new size for the
616  * memtuples array. The optimal value might be higher or lower than
617  * this estimate, but it's hard to know that in advance. We again
618  * clamp at INT_MAX tuples.
619  *
620  * This calculation is safe against enlarging the array so much that
621  * LACKMEM becomes true, because the memory currently used includes
622  * the present array; thus, there would be enough allowedMem for the
623  * new array elements even if no other memory were currently used.
624  *
625  * We do the arithmetic in float8, because otherwise the product of
626  * memtupsize and allowedMem could overflow. Any inaccuracy in the
627  * result should be insignificant; but even if we computed a
628  * completely insane result, the checks below will prevent anything
629  * really bad from happening.
630  */
631  double grow_ratio;
632 
633  grow_ratio = (double) state->allowedMem / (double) memNowUsed;
634  if (memtupsize * grow_ratio < INT_MAX)
635  newmemtupsize = (int) (memtupsize * grow_ratio);
636  else
637  newmemtupsize = INT_MAX;
638 
639  /* We won't make any further enlargement attempts */
640  state->growmemtuples = false;
641  }
642 
643  /* Must enlarge array by at least one element, else report failure */
644  if (newmemtupsize <= memtupsize)
645  goto noalloc;
646 
647  /*
648  * On a 32-bit machine, allowedMem could exceed MaxAllocHugeSize. Clamp
649  * to ensure our request won't be rejected. Note that we can easily
650  * exhaust address space before facing this outcome. (This is presently
651  * impossible due to guc.c's MAX_KILOBYTES limitation on work_mem, but
652  * don't rely on that at this distance.)
653  */
654  if ((Size) newmemtupsize >= MaxAllocHugeSize / sizeof(void *))
655  {
656  newmemtupsize = (int) (MaxAllocHugeSize / sizeof(void *));
657  state->growmemtuples = false; /* can't grow any more */
658  }
659 
660  /*
661  * We need to be sure that we do not cause LACKMEM to become true, else
662  * the space management algorithm will go nuts. The code above should
663  * never generate a dangerous request, but to be safe, check explicitly
664  * that the array growth fits within availMem. (We could still cause
665  * LACKMEM if the memory chunk overhead associated with the memtuples
666  * array were to increase. That shouldn't happen because we chose the
667  * initial array size large enough to ensure that palloc will be treating
668  * both old and new arrays as separate chunks. But we'll check LACKMEM
669  * explicitly below just in case.)
670  */
671  if (state->availMem < (int64) ((newmemtupsize - memtupsize) * sizeof(void *)))
672  goto noalloc;
673 
674  /* OK, do it */
675  FREEMEM(state, GetMemoryChunkSpace(state->memtuples));
676  state->memtupsize = newmemtupsize;
677  state->memtuples = (void **)
678  repalloc_huge(state->memtuples,
679  state->memtupsize * sizeof(void *));
680  USEMEM(state, GetMemoryChunkSpace(state->memtuples));
681  if (LACKMEM(state))
682  elog(ERROR, "unexpected out-of-memory situation in tuplestore");
683  return true;
684 
685 noalloc:
686  /* If for any reason we didn't realloc, shut off future attempts */
687  state->growmemtuples = false;
688  return false;
689 }
size_t Size
Definition: c.h:592
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
void * repalloc_huge(void *pointer, Size size)
Definition: mcxt.c:1659
#define MaxAllocHugeSize
Definition: memutils.h:45
#define LACKMEM(state)
Definition: tuplestore.c:186
#define FREEMEM(state, amt)
Definition: tuplestore.c:188

References elog, ERROR, FREEMEM, GetMemoryChunkSpace(), LACKMEM, MaxAllocHugeSize, repalloc_huge(), and USEMEM.

Referenced by tuplestore_puttuple_common().

◆ readtup_heap()

static void * readtup_heap ( Tuplestorestate state,
unsigned int  len 
)
static

Definition at line 1521 of file tuplestore.c.

1522 {
1523  unsigned int tupbodylen = len - sizeof(int);
1524  unsigned int tuplen = tupbodylen + MINIMAL_TUPLE_DATA_OFFSET;
1525  MinimalTuple tuple = (MinimalTuple) palloc(tuplen);
1526  char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
1527 
1528  USEMEM(state, GetMemoryChunkSpace(tuple));
1529  /* read in the tuple proper */
1530  tuple->t_len = tuplen;
1531  BufFileReadExact(state->myfile, tupbody, tupbodylen);
1532  if (state->backward) /* need trailing length word? */
1533  BufFileReadExact(state->myfile, &tuplen, sizeof(tuplen));
1534  return (void *) tuple;
1535 }
void BufFileReadExact(BufFile *file, void *ptr, size_t size)
Definition: buffile.c:654
MinimalTupleData * MinimalTuple
Definition: htup.h:27
#define MINIMAL_TUPLE_DATA_OFFSET
Definition: htup_details.h:621
void * palloc(Size size)
Definition: mcxt.c:1304

References BufFileReadExact(), GetMemoryChunkSpace(), len, MINIMAL_TUPLE_DATA_OFFSET, palloc(), MinimalTupleData::t_len, and USEMEM.

Referenced by tuplestore_begin_heap().

◆ tuplestore_advance()

bool tuplestore_advance ( Tuplestorestate state,
bool  forward 
)

Definition at line 1110 of file tuplestore.c.

1111 {
1112  void *tuple;
1113  bool should_free;
1114 
1115  tuple = tuplestore_gettuple(state, forward, &should_free);
1116 
1117  if (tuple)
1118  {
1119  if (should_free)
1120  pfree(tuple);
1121  return true;
1122  }
1123  else
1124  {
1125  return false;
1126  }
1127 }
void pfree(void *pointer)
Definition: mcxt.c:1508
static void * tuplestore_gettuple(Tuplestorestate *state, bool forward, bool *should_free)
Definition: tuplestore.c:903

References pfree(), and tuplestore_gettuple().

Referenced by CteScanNext(), ExecMaterial(), and window_gettupleslot().

◆ tuplestore_alloc_read_pointer()

int tuplestore_alloc_read_pointer ( Tuplestorestate state,
int  eflags 
)

Definition at line 383 of file tuplestore.c.

384 {
385  /* Check for possible increase of requirements */
386  if (state->status != TSS_INMEM || state->memtupcount != 0)
387  {
388  if ((state->eflags | eflags) != state->eflags)
389  elog(ERROR, "too late to require new tuplestore eflags");
390  }
391 
392  /* Make room for another read pointer if needed */
393  if (state->readptrcount >= state->readptrsize)
394  {
395  int newcnt = state->readptrsize * 2;
396 
397  state->readptrs = (TSReadPointer *)
398  repalloc(state->readptrs, newcnt * sizeof(TSReadPointer));
399  state->readptrsize = newcnt;
400  }
401 
402  /* And set it up */
403  state->readptrs[state->readptrcount] = state->readptrs[0];
404  state->readptrs[state->readptrcount].eflags = eflags;
405 
406  state->eflags |= eflags;
407 
408  return state->readptrcount++;
409 }
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1528

References elog, ERROR, repalloc(), and TSS_INMEM.

Referenced by begin_partition(), ExecInitCteScan(), ExecInitNamedTuplestoreScan(), and ExecMaterial().

◆ tuplestore_ateof()

bool tuplestore_ateof ( Tuplestorestate state)

Definition at line 557 of file tuplestore.c.

558 {
559  return state->readptrs[state->activeptr].eof_reached;
560 }

Referenced by CteScanNext(), and ExecMaterial().

◆ tuplestore_begin_common()

static Tuplestorestate * tuplestore_begin_common ( int  eflags,
bool  interXact,
int  maxKBytes 
)
static

Definition at line 253 of file tuplestore.c.

254 {
256 
258 
259  state->status = TSS_INMEM;
260  state->eflags = eflags;
261  state->interXact = interXact;
262  state->truncated = false;
263  state->allowedMem = maxKBytes * 1024L;
264  state->availMem = state->allowedMem;
265  state->myfile = NULL;
266  state->context = CurrentMemoryContext;
267  state->resowner = CurrentResourceOwner;
268 
269  state->memtupdeleted = 0;
270  state->memtupcount = 0;
271  state->tuples = 0;
272 
273  /*
274  * Initial size of array must be more than ALLOCSET_SEPARATE_THRESHOLD;
275  * see comments in grow_memtuples().
276  */
277  state->memtupsize = Max(16384 / sizeof(void *),
278  ALLOCSET_SEPARATE_THRESHOLD / sizeof(void *) + 1);
279 
280  state->growmemtuples = true;
281  state->memtuples = (void **) palloc(state->memtupsize * sizeof(void *));
282 
283  USEMEM(state, GetMemoryChunkSpace(state->memtuples));
284 
285  state->activeptr = 0;
286  state->readptrcount = 1;
287  state->readptrsize = 8; /* arbitrary */
288  state->readptrs = (TSReadPointer *)
289  palloc(state->readptrsize * sizeof(TSReadPointer));
290 
291  state->readptrs[0].eflags = eflags;
292  state->readptrs[0].eof_reached = false;
293  state->readptrs[0].current = 0;
294 
295  return state;
296 }
#define Max(x, y)
Definition: c.h:985
void * palloc0(Size size)
Definition: mcxt.c:1334
MemoryContext CurrentMemoryContext
Definition: mcxt.c:131
#define ALLOCSET_SEPARATE_THRESHOLD
Definition: memutils.h:180
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165

References ALLOCSET_SEPARATE_THRESHOLD, CurrentMemoryContext, CurrentResourceOwner, GetMemoryChunkSpace(), Max, palloc(), palloc0(), TSS_INMEM, and USEMEM.

Referenced by tuplestore_begin_heap().

◆ tuplestore_begin_heap()

Tuplestorestate* tuplestore_begin_heap ( bool  randomAccess,
bool  interXact,
int  maxKBytes 
)

Definition at line 318 of file tuplestore.c.

319 {
321  int eflags;
322 
323  /*
324  * This interpretation of the meaning of randomAccess is compatible with
325  * the pre-8.3 behavior of tuplestores.
326  */
327  eflags = randomAccess ?
330 
331  state = tuplestore_begin_common(eflags, interXact, maxKBytes);
332 
333  state->copytup = copytup_heap;
334  state->writetup = writetup_heap;
335  state->readtup = readtup_heap;
336 
337  return state;
338 }
#define EXEC_FLAG_BACKWARD
Definition: executor.h:68
#define EXEC_FLAG_REWIND
Definition: executor.h:67
static void writetup_heap(Tuplestorestate *state, void *tup)
Definition: tuplestore.c:1500
static void * copytup_heap(Tuplestorestate *state, void *tup)
Definition: tuplestore.c:1490
static Tuplestorestate * tuplestore_begin_common(int eflags, bool interXact, int maxKBytes)
Definition: tuplestore.c:253
static void * readtup_heap(Tuplestorestate *state, unsigned int len)
Definition: tuplestore.c:1521

References copytup_heap(), EXEC_FLAG_BACKWARD, EXEC_FLAG_REWIND, readtup_heap(), tuplestore_begin_common(), and writetup_heap().

Referenced by begin_partition(), connectby(), crosstab(), exec_init_tuple_store(), ExecInitCteScan(), ExecInitRecursiveUnion(), ExecMakeTableFunctionResult(), ExecMaterial(), ExecRecursiveUnion(), fmgr_sql(), get_crosstab_tuplestore(), GetCurrentFDWTuplestore(), InitMaterializedSRF(), libpqrcv_processTuples(), MakeTransitionCaptureState(), materializeResult(), plperl_return_next_internal(), pltcl_init_tuple_store(), populate_recordset_worker(), PortalCreateHoldStore(), storeRow(), and tfuncFetchRows().

◆ tuplestore_clear()

void tuplestore_clear ( Tuplestorestate state)

Definition at line 418 of file tuplestore.c.

419 {
420  int i;
421  TSReadPointer *readptr;
422 
423  if (state->myfile)
424  BufFileClose(state->myfile);
425  state->myfile = NULL;
426  if (state->memtuples)
427  {
428  for (i = state->memtupdeleted; i < state->memtupcount; i++)
429  {
430  FREEMEM(state, GetMemoryChunkSpace(state->memtuples[i]));
431  pfree(state->memtuples[i]);
432  }
433  }
434  state->status = TSS_INMEM;
435  state->truncated = false;
436  state->memtupdeleted = 0;
437  state->memtupcount = 0;
438  state->tuples = 0;
439  readptr = state->readptrs;
440  for (i = 0; i < state->readptrcount; readptr++, i++)
441  {
442  readptr->eof_reached = false;
443  readptr->current = 0;
444  }
445 }
void BufFileClose(BufFile *file)
Definition: buffile.c:412

References BufFileClose(), TSReadPointer::current, TSReadPointer::eof_reached, FREEMEM, GetMemoryChunkSpace(), i, pfree(), and TSS_INMEM.

Referenced by ExecReScanCteScan(), ExecReScanRecursiveUnion(), and fmgr_sql().

◆ tuplestore_copy_read_pointer()

void tuplestore_copy_read_pointer ( Tuplestorestate state,
int  srcptr,
int  destptr 
)

Definition at line 1268 of file tuplestore.c.

1270 {
1271  TSReadPointer *sptr = &state->readptrs[srcptr];
1272  TSReadPointer *dptr = &state->readptrs[destptr];
1273 
1274  Assert(srcptr >= 0 && srcptr < state->readptrcount);
1275  Assert(destptr >= 0 && destptr < state->readptrcount);
1276 
1277  /* Assigning to self is a no-op */
1278  if (srcptr == destptr)
1279  return;
1280 
1281  if (dptr->eflags != sptr->eflags)
1282  {
1283  /* Possible change of overall eflags, so copy and then recompute */
1284  int eflags;
1285  int i;
1286 
1287  *dptr = *sptr;
1288  eflags = state->readptrs[0].eflags;
1289  for (i = 1; i < state->readptrcount; i++)
1290  eflags |= state->readptrs[i].eflags;
1291  state->eflags = eflags;
1292  }
1293  else
1294  *dptr = *sptr;
1295 
1296  switch (state->status)
1297  {
1298  case TSS_INMEM:
1299  case TSS_WRITEFILE:
1300  /* no work */
1301  break;
1302  case TSS_READFILE:
1303 
1304  /*
1305  * This case is a bit tricky since the active read pointer's
1306  * position corresponds to the seek point, not what is in its
1307  * variables. Assigning to the active requires a seek, and
1308  * assigning from the active requires a tell, except when
1309  * eof_reached.
1310  */
1311  if (destptr == state->activeptr)
1312  {
1313  if (dptr->eof_reached)
1314  {
1315  if (BufFileSeek(state->myfile,
1316  state->writepos_file,
1317  state->writepos_offset,
1318  SEEK_SET) != 0)
1319  ereport(ERROR,
1321  errmsg("could not seek in tuplestore temporary file")));
1322  }
1323  else
1324  {
1325  if (BufFileSeek(state->myfile,
1326  dptr->file, dptr->offset,
1327  SEEK_SET) != 0)
1328  ereport(ERROR,
1330  errmsg("could not seek in tuplestore temporary file")));
1331  }
1332  }
1333  else if (srcptr == state->activeptr)
1334  {
1335  if (!dptr->eof_reached)
1336  BufFileTell(state->myfile,
1337  &dptr->file,
1338  &dptr->offset);
1339  }
1340  break;
1341  default:
1342  elog(ERROR, "invalid tuplestore state");
1343  break;
1344  }
1345 }
int BufFileSeek(BufFile *file, int fileno, off_t offset, int whence)
Definition: buffile.c:740
int errcode_for_file_access(void)
Definition: elog.c:882
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ereport(elevel,...)
Definition: elog.h:149
Assert(fmt[strlen(fmt) - 1] !='\n')

References Assert(), BufFileSeek(), BufFileTell(), TSReadPointer::eflags, elog, TSReadPointer::eof_reached, ereport, errcode_for_file_access(), errmsg(), ERROR, TSReadPointer::file, i, TSReadPointer::offset, TSS_INMEM, TSS_READFILE, and TSS_WRITEFILE.

Referenced by ExecMaterialMarkPos(), and ExecMaterialRestrPos().

◆ tuplestore_end()

void tuplestore_end ( Tuplestorestate state)

Definition at line 453 of file tuplestore.c.

454 {
455  int i;
456 
457  if (state->myfile)
458  BufFileClose(state->myfile);
459  if (state->memtuples)
460  {
461  for (i = state->memtupdeleted; i < state->memtupcount; i++)
462  pfree(state->memtuples[i]);
463  pfree(state->memtuples);
464  }
465  pfree(state->readptrs);
466  pfree(state);
467 }

References BufFileClose(), i, and pfree().

Referenced by AfterTriggerFreeQuery(), ExecEndCteScan(), ExecEndFunctionScan(), ExecEndMaterial(), ExecEndRecursiveUnion(), ExecEndTableFuncScan(), ExecMakeFunctionResultSet(), ExecRecursiveUnion(), ExecReScanFunctionScan(), ExecReScanMaterial(), ExecReScanTableFuncScan(), PortalDrop(), release_partition(), ShutdownSetExpr(), ShutdownSQLFunction(), storeRow(), and walrcv_clear_result().

◆ tuplestore_gettuple()

static void* tuplestore_gettuple ( Tuplestorestate state,
bool  forward,
bool should_free 
)
static

Definition at line 903 of file tuplestore.c.

905 {
906  TSReadPointer *readptr = &state->readptrs[state->activeptr];
907  unsigned int tuplen;
908  void *tup;
909 
910  Assert(forward || (readptr->eflags & EXEC_FLAG_BACKWARD));
911 
912  switch (state->status)
913  {
914  case TSS_INMEM:
915  *should_free = false;
916  if (forward)
917  {
918  if (readptr->eof_reached)
919  return NULL;
920  if (readptr->current < state->memtupcount)
921  {
922  /* We have another tuple, so return it */
923  return state->memtuples[readptr->current++];
924  }
925  readptr->eof_reached = true;
926  return NULL;
927  }
928  else
929  {
930  /*
931  * if all tuples are fetched already then we return last
932  * tuple, else tuple before last returned.
933  */
934  if (readptr->eof_reached)
935  {
936  readptr->current = state->memtupcount;
937  readptr->eof_reached = false;
938  }
939  else
940  {
941  if (readptr->current <= state->memtupdeleted)
942  {
943  Assert(!state->truncated);
944  return NULL;
945  }
946  readptr->current--; /* last returned tuple */
947  }
948  if (readptr->current <= state->memtupdeleted)
949  {
950  Assert(!state->truncated);
951  return NULL;
952  }
953  return state->memtuples[readptr->current - 1];
954  }
955  break;
956 
957  case TSS_WRITEFILE:
958  /* Skip state change if we'll just return NULL */
959  if (readptr->eof_reached && forward)
960  return NULL;
961 
962  /*
963  * Switch from writing to reading.
964  */
965  BufFileTell(state->myfile,
966  &state->writepos_file, &state->writepos_offset);
967  if (!readptr->eof_reached)
968  if (BufFileSeek(state->myfile,
969  readptr->file, readptr->offset,
970  SEEK_SET) != 0)
971  ereport(ERROR,
973  errmsg("could not seek in tuplestore temporary file")));
974  state->status = TSS_READFILE;
975  /* FALLTHROUGH */
976 
977  case TSS_READFILE:
978  *should_free = true;
979  if (forward)
980  {
981  if ((tuplen = getlen(state, true)) != 0)
982  {
983  tup = READTUP(state, tuplen);
984  return tup;
985  }
986  else
987  {
988  readptr->eof_reached = true;
989  return NULL;
990  }
991  }
992 
993  /*
994  * Backward.
995  *
996  * if all tuples are fetched already then we return last tuple,
997  * else tuple before last returned.
998  *
999  * Back up to fetch previously-returned tuple's ending length
1000  * word. If seek fails, assume we are at start of file.
1001  */
1002  if (BufFileSeek(state->myfile, 0, -(long) sizeof(unsigned int),
1003  SEEK_CUR) != 0)
1004  {
1005  /* even a failed backwards fetch gets you out of eof state */
1006  readptr->eof_reached = false;
1007  Assert(!state->truncated);
1008  return NULL;
1009  }
1010  tuplen = getlen(state, false);
1011 
1012  if (readptr->eof_reached)
1013  {
1014  readptr->eof_reached = false;
1015  /* We will return the tuple returned before returning NULL */
1016  }
1017  else
1018  {
1019  /*
1020  * Back up to get ending length word of tuple before it.
1021  */
1022  if (BufFileSeek(state->myfile, 0,
1023  -(long) (tuplen + 2 * sizeof(unsigned int)),
1024  SEEK_CUR) != 0)
1025  {
1026  /*
1027  * If that fails, presumably the prev tuple is the first
1028  * in the file. Back up so that it becomes next to read
1029  * in forward direction (not obviously right, but that is
1030  * what in-memory case does).
1031  */
1032  if (BufFileSeek(state->myfile, 0,
1033  -(long) (tuplen + sizeof(unsigned int)),
1034  SEEK_CUR) != 0)
1035  ereport(ERROR,
1037  errmsg("could not seek in tuplestore temporary file")));
1038  Assert(!state->truncated);
1039  return NULL;
1040  }
1041  tuplen = getlen(state, false);
1042  }
1043 
1044  /*
1045  * Now we have the length of the prior tuple, back up and read it.
1046  * Note: READTUP expects we are positioned after the initial
1047  * length word of the tuple, so back up to that point.
1048  */
1049  if (BufFileSeek(state->myfile, 0,
1050  -(long) tuplen,
1051  SEEK_CUR) != 0)
1052  ereport(ERROR,
1054  errmsg("could not seek in tuplestore temporary file")));
1055  tup = READTUP(state, tuplen);
1056  return tup;
1057 
1058  default:
1059  elog(ERROR, "invalid tuplestore state");
1060  return NULL; /* keep compiler quiet */
1061  }
1062 }
#define READTUP(state, len)
Definition: tuplestore.c:185
static unsigned int getlen(Tuplestorestate *state, bool eofOK)
Definition: tuplestore.c:1466

References Assert(), BufFileSeek(), BufFileTell(), TSReadPointer::current, TSReadPointer::eflags, elog, TSReadPointer::eof_reached, ereport, errcode_for_file_access(), errmsg(), ERROR, EXEC_FLAG_BACKWARD, TSReadPointer::file, getlen(), TSReadPointer::offset, READTUP, TSS_INMEM, TSS_READFILE, and TSS_WRITEFILE.

Referenced by tuplestore_advance(), tuplestore_gettupleslot(), and tuplestore_skiptuples().

◆ tuplestore_gettupleslot()

bool tuplestore_gettupleslot ( Tuplestorestate state,
bool  forward,
bool  copy,
TupleTableSlot slot 
)

Definition at line 1078 of file tuplestore.c.

1080 {
1081  MinimalTuple tuple;
1082  bool should_free;
1083 
1084  tuple = (MinimalTuple) tuplestore_gettuple(state, forward, &should_free);
1085 
1086  if (tuple)
1087  {
1088  if (copy && !should_free)
1089  {
1090  tuple = heap_copy_minimal_tuple(tuple);
1091  should_free = true;
1092  }
1093  ExecStoreMinimalTuple(tuple, slot, should_free);
1094  return true;
1095  }
1096  else
1097  {
1098  ExecClearTuple(slot);
1099  return false;
1100  }
1101 }
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
Definition: execTuples.c:1445
MinimalTuple heap_copy_minimal_tuple(MinimalTuple mtup)
Definition: heaptuple.c:1535
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:433

References ExecClearTuple(), ExecStoreMinimalTuple(), heap_copy_minimal_tuple(), and tuplestore_gettuple().

Referenced by AfterTriggerExecute(), check_publications(), check_publications_origin(), CteScanNext(), ExecMakeFunctionResultSet(), ExecMaterial(), ExecWindowAgg(), fetch_remote_table_info(), fetch_table_list(), fmgr_sql(), FunctionNext(), NamedTuplestoreScanNext(), RunFromStore(), synchronize_slots(), TableFuncNext(), update_frameheadpos(), update_frametailpos(), update_grouptailpos(), validate_remote_info(), window_gettupleslot(), and WorkTableScanNext().

◆ tuplestore_in_memory()

bool tuplestore_in_memory ( Tuplestorestate state)

Definition at line 1455 of file tuplestore.c.

1456 {
1457  return (state->status == TSS_INMEM);
1458 }

References TSS_INMEM.

Referenced by spool_tuples().

◆ tuplestore_puttuple()

void tuplestore_puttuple ( Tuplestorestate state,
HeapTuple  tuple 
)

Definition at line 730 of file tuplestore.c.

731 {
732  MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
733 
734  /*
735  * Copy the tuple. (Must do this even in WRITEFILE case. Note that
736  * COPYTUP includes USEMEM, so we needn't do that here.)
737  */
738  tuple = COPYTUP(state, tuple);
739 
740  tuplestore_puttuple_common(state, (void *) tuple);
741 
742  MemoryContextSwitchTo(oldcxt);
743 }
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define COPYTUP(state, tup)
Definition: tuplestore.c:183
static void tuplestore_puttuple_common(Tuplestorestate *state, void *tuple)
Definition: tuplestore.c:765

References COPYTUP, MemoryContextSwitchTo(), and tuplestore_puttuple_common().

Referenced by build_tuplestore_recursively(), crosstab(), each_object_field_end(), elements_array_element_end(), exec_stmt_return_next(), ExecMakeTableFunctionResult(), fill_hba_line(), fill_ident_line(), get_crosstab_tuplestore(), libpqrcv_processTuples(), materializeResult(), pg_available_wal_summaries(), pg_wal_summary_contents(), pgrowlocks(), plperl_return_next_internal(), pltcl_returnnext(), populate_recordset_record(), report_corruption_internal(), storeRow(), and xpath_table().

◆ tuplestore_puttuple_common()

static void tuplestore_puttuple_common ( Tuplestorestate state,
void *  tuple 
)
static

Definition at line 765 of file tuplestore.c.

766 {
767  TSReadPointer *readptr;
768  int i;
769  ResourceOwner oldowner;
770 
771  state->tuples++;
772 
773  switch (state->status)
774  {
775  case TSS_INMEM:
776 
777  /*
778  * Update read pointers as needed; see API spec above.
779  */
780  readptr = state->readptrs;
781  for (i = 0; i < state->readptrcount; readptr++, i++)
782  {
783  if (readptr->eof_reached && i != state->activeptr)
784  {
785  readptr->eof_reached = false;
786  readptr->current = state->memtupcount;
787  }
788  }
789 
790  /*
791  * Grow the array as needed. Note that we try to grow the array
792  * when there is still one free slot remaining --- if we fail,
793  * there'll still be room to store the incoming tuple, and then
794  * we'll switch to tape-based operation.
795  */
796  if (state->memtupcount >= state->memtupsize - 1)
797  {
798  (void) grow_memtuples(state);
799  Assert(state->memtupcount < state->memtupsize);
800  }
801 
802  /* Stash the tuple in the in-memory array */
803  state->memtuples[state->memtupcount++] = tuple;
804 
805  /*
806  * Done if we still fit in available memory and have array slots.
807  */
808  if (state->memtupcount < state->memtupsize && !LACKMEM(state))
809  return;
810 
811  /*
812  * Nope; time to switch to tape-based operation. Make sure that
813  * the temp file(s) are created in suitable temp tablespaces.
814  */
816 
817  /* associate the file with the store's resource owner */
818  oldowner = CurrentResourceOwner;
819  CurrentResourceOwner = state->resowner;
820 
821  state->myfile = BufFileCreateTemp(state->interXact);
822 
823  CurrentResourceOwner = oldowner;
824 
825  /*
826  * Freeze the decision about whether trailing length words will be
827  * used. We can't change this choice once data is on tape, even
828  * though callers might drop the requirement.
829  */
830  state->backward = (state->eflags & EXEC_FLAG_BACKWARD) != 0;
831  state->status = TSS_WRITEFILE;
832  dumptuples(state);
833  break;
834  case TSS_WRITEFILE:
835 
836  /*
837  * Update read pointers as needed; see API spec above. Note:
838  * BufFileTell is quite cheap, so not worth trying to avoid
839  * multiple calls.
840  */
841  readptr = state->readptrs;
842  for (i = 0; i < state->readptrcount; readptr++, i++)
843  {
844  if (readptr->eof_reached && i != state->activeptr)
845  {
846  readptr->eof_reached = false;
847  BufFileTell(state->myfile,
848  &readptr->file,
849  &readptr->offset);
850  }
851  }
852 
853  WRITETUP(state, tuple);
854  break;
855  case TSS_READFILE:
856 
857  /*
858  * Switch from reading to writing.
859  */
860  if (!state->readptrs[state->activeptr].eof_reached)
861  BufFileTell(state->myfile,
862  &state->readptrs[state->activeptr].file,
863  &state->readptrs[state->activeptr].offset);
864  if (BufFileSeek(state->myfile,
865  state->writepos_file, state->writepos_offset,
866  SEEK_SET) != 0)
867  ereport(ERROR,
869  errmsg("could not seek in tuplestore temporary file")));
870  state->status = TSS_WRITEFILE;
871 
872  /*
873  * Update read pointers as needed; see API spec above.
874  */
875  readptr = state->readptrs;
876  for (i = 0; i < state->readptrcount; readptr++, i++)
877  {
878  if (readptr->eof_reached && i != state->activeptr)
879  {
880  readptr->eof_reached = false;
881  readptr->file = state->writepos_file;
882  readptr->offset = state->writepos_offset;
883  }
884  }
885 
886  WRITETUP(state, tuple);
887  break;
888  default:
889  elog(ERROR, "invalid tuplestore state");
890  break;
891  }
892 }
void PrepareTempTablespaces(void)
Definition: tablespace.c:1331
BufFile * BufFileCreateTemp(bool interXact)
Definition: buffile.c:193
static bool grow_memtuples(Tuplestorestate *state)
Definition: tuplestore.c:578
static void dumptuples(Tuplestorestate *state)
Definition: tuplestore.c:1206

References Assert(), BufFileCreateTemp(), BufFileSeek(), BufFileTell(), TSReadPointer::current, CurrentResourceOwner, dumptuples(), elog, TSReadPointer::eof_reached, ereport, errcode_for_file_access(), errmsg(), ERROR, EXEC_FLAG_BACKWARD, TSReadPointer::file, grow_memtuples(), i, LACKMEM, TSReadPointer::offset, PrepareTempTablespaces(), TSS_INMEM, TSS_READFILE, TSS_WRITEFILE, and WRITETUP.

Referenced by tuplestore_puttuple(), tuplestore_puttupleslot(), and tuplestore_putvalues().

◆ tuplestore_puttupleslot()

void tuplestore_puttupleslot ( Tuplestorestate state,
TupleTableSlot slot 
)

Definition at line 708 of file tuplestore.c.

710 {
711  MinimalTuple tuple;
712  MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
713 
714  /*
715  * Form a MinimalTuple in working memory
716  */
717  tuple = ExecCopySlotMinimalTuple(slot);
719 
720  tuplestore_puttuple_common(state, (void *) tuple);
721 
722  MemoryContextSwitchTo(oldcxt);
723 }
static MinimalTuple ExecCopySlotMinimalTuple(TupleTableSlot *slot)
Definition: tuptable.h:471

References ExecCopySlotMinimalTuple(), GetMemoryChunkSpace(), MemoryContextSwitchTo(), tuplestore_puttuple_common(), and USEMEM.

Referenced by AfterTriggerSaveEvent(), begin_partition(), CteScanNext(), ExecMaterial(), ExecRecursiveUnion(), spool_tuples(), sqlfunction_receive(), TransitionTableAddTuple(), tstoreReceiveSlot_notoast(), and tstoreReceiveSlot_tupmap().

◆ tuplestore_putvalues()

void tuplestore_putvalues ( Tuplestorestate state,
TupleDesc  tdesc,
const Datum values,
const bool isnull 
)

Definition at line 750 of file tuplestore.c.

752 {
753  MinimalTuple tuple;
754  MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
755 
756  tuple = heap_form_minimal_tuple(tdesc, values, isnull);
758 
759  tuplestore_puttuple_common(state, (void *) tuple);
760 
761  MemoryContextSwitchTo(oldcxt);
762 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
MinimalTuple heap_form_minimal_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1452

References GetMemoryChunkSpace(), heap_form_minimal_tuple(), MemoryContextSwitchTo(), tuplestore_puttuple_common(), USEMEM, and values.

Referenced by brin_page_items(), dblink_get_notify(), each_worker_jsonb(), elements_worker_jsonb(), exec_stmt_return_next(), ExecMakeTableFunctionResult(), get_altertable_subcmdinfo(), get_available_versions_for_extension(), GetWALBlockInfo(), GetWALRecordsInfo(), GetXLogSummaryStats(), gist_page_items(), gist_page_items_bytea(), LogicalOutputWrite(), pg_available_extensions(), pg_config(), pg_cursor(), pg_event_trigger_ddl_commands(), pg_event_trigger_dropped_objects(), pg_extension_update_paths(), pg_get_replication_slots(), pg_get_shmem_allocations(), pg_get_wait_events(), pg_ls_dir(), pg_ls_dir_files(), pg_prepared_statement(), pg_show_replication_origin_status(), pg_stat_get_activity(), pg_stat_get_io(), pg_stat_get_progress_info(), pg_stat_get_recovery_prefetch(), pg_stat_get_slru(), pg_stat_get_subscription(), pg_stat_get_wal_senders(), pg_stat_statements_internal(), pg_tablespace_databases(), plperl_return_next_internal(), pltcl_returnnext(), postgres_fdw_get_connections(), PutMemoryContextsStatsTupleStore(), show_all_file_settings(), split_text_accum_result(), tfuncLoadRows(), and tstoreReceiveSlot_detoast().

◆ tuplestore_rescan()

void tuplestore_rescan ( Tuplestorestate state)

Definition at line 1233 of file tuplestore.c.

1234 {
1235  TSReadPointer *readptr = &state->readptrs[state->activeptr];
1236 
1237  Assert(readptr->eflags & EXEC_FLAG_REWIND);
1238  Assert(!state->truncated);
1239 
1240  switch (state->status)
1241  {
1242  case TSS_INMEM:
1243  readptr->eof_reached = false;
1244  readptr->current = 0;
1245  break;
1246  case TSS_WRITEFILE:
1247  readptr->eof_reached = false;
1248  readptr->file = 0;
1249  readptr->offset = 0;
1250  break;
1251  case TSS_READFILE:
1252  readptr->eof_reached = false;
1253  if (BufFileSeek(state->myfile, 0, 0, SEEK_SET) != 0)
1254  ereport(ERROR,
1256  errmsg("could not seek in tuplestore temporary file")));
1257  break;
1258  default:
1259  elog(ERROR, "invalid tuplestore state");
1260  break;
1261  }
1262 }

References Assert(), BufFileSeek(), TSReadPointer::current, TSReadPointer::eflags, elog, TSReadPointer::eof_reached, ereport, errcode_for_file_access(), errmsg(), ERROR, EXEC_FLAG_REWIND, TSReadPointer::file, TSReadPointer::offset, TSS_INMEM, TSS_READFILE, and TSS_WRITEFILE.

Referenced by DoPortalRewind(), ExecInitCteScan(), ExecInitNamedTuplestoreScan(), ExecReScanCteScan(), ExecReScanFunctionScan(), ExecReScanMaterial(), ExecReScanNamedTuplestoreScan(), ExecReScanTableFuncScan(), ExecReScanWorkTableScan(), FunctionNext(), and PersistHoldablePortal().

◆ tuplestore_select_read_pointer()

void tuplestore_select_read_pointer ( Tuplestorestate state,
int  ptr 
)

Definition at line 473 of file tuplestore.c.

474 {
475  TSReadPointer *readptr;
476  TSReadPointer *oldptr;
477 
478  Assert(ptr >= 0 && ptr < state->readptrcount);
479 
480  /* No work if already active */
481  if (ptr == state->activeptr)
482  return;
483 
484  readptr = &state->readptrs[ptr];
485  oldptr = &state->readptrs[state->activeptr];
486 
487  switch (state->status)
488  {
489  case TSS_INMEM:
490  case TSS_WRITEFILE:
491  /* no work */
492  break;
493  case TSS_READFILE:
494 
495  /*
496  * First, save the current read position in the pointer about to
497  * become inactive.
498  */
499  if (!oldptr->eof_reached)
500  BufFileTell(state->myfile,
501  &oldptr->file,
502  &oldptr->offset);
503 
504  /*
505  * We have to make the temp file's seek position equal to the
506  * logical position of the new read pointer. In eof_reached
507  * state, that's the EOF, which we have available from the saved
508  * write position.
509  */
510  if (readptr->eof_reached)
511  {
512  if (BufFileSeek(state->myfile,
513  state->writepos_file,
514  state->writepos_offset,
515  SEEK_SET) != 0)
516  ereport(ERROR,
518  errmsg("could not seek in tuplestore temporary file")));
519  }
520  else
521  {
522  if (BufFileSeek(state->myfile,
523  readptr->file,
524  readptr->offset,
525  SEEK_SET) != 0)
526  ereport(ERROR,
528  errmsg("could not seek in tuplestore temporary file")));
529  }
530  break;
531  default:
532  elog(ERROR, "invalid tuplestore state");
533  break;
534  }
535 
536  state->activeptr = ptr;
537 }

References Assert(), BufFileSeek(), BufFileTell(), elog, TSReadPointer::eof_reached, ereport, errcode_for_file_access(), errmsg(), ERROR, TSReadPointer::file, TSReadPointer::offset, TSS_INMEM, TSS_READFILE, and TSS_WRITEFILE.

Referenced by CteScanNext(), ExecInitCteScan(), ExecInitNamedTuplestoreScan(), ExecReScanCteScan(), ExecReScanNamedTuplestoreScan(), ExecWindowAgg(), NamedTuplestoreScanNext(), update_frameheadpos(), update_frametailpos(), update_grouptailpos(), window_gettupleslot(), and WinSetMarkPosition().

◆ tuplestore_set_eflags()

void tuplestore_set_eflags ( Tuplestorestate state,
int  eflags 
)

Definition at line 359 of file tuplestore.c.

360 {
361  int i;
362 
363  if (state->status != TSS_INMEM || state->memtupcount != 0)
364  elog(ERROR, "too late to call tuplestore_set_eflags");
365 
366  state->readptrs[0].eflags = eflags;
367  for (i = 1; i < state->readptrcount; i++)
368  eflags |= state->readptrs[i].eflags;
369  state->eflags = eflags;
370 }

References elog, ERROR, i, and TSS_INMEM.

Referenced by begin_partition(), ExecInitCteScan(), and ExecMaterial().

◆ tuplestore_skiptuples()

bool tuplestore_skiptuples ( Tuplestorestate state,
int64  ntuples,
bool  forward 
)

Definition at line 1135 of file tuplestore.c.

1136 {
1137  TSReadPointer *readptr = &state->readptrs[state->activeptr];
1138 
1139  Assert(forward || (readptr->eflags & EXEC_FLAG_BACKWARD));
1140 
1141  if (ntuples <= 0)
1142  return true;
1143 
1144  switch (state->status)
1145  {
1146  case TSS_INMEM:
1147  if (forward)
1148  {
1149  if (readptr->eof_reached)
1150  return false;
1151  if (state->memtupcount - readptr->current >= ntuples)
1152  {
1153  readptr->current += ntuples;
1154  return true;
1155  }
1156  readptr->current = state->memtupcount;
1157  readptr->eof_reached = true;
1158  return false;
1159  }
1160  else
1161  {
1162  if (readptr->eof_reached)
1163  {
1164  readptr->current = state->memtupcount;
1165  readptr->eof_reached = false;
1166  ntuples--;
1167  }
1168  if (readptr->current - state->memtupdeleted > ntuples)
1169  {
1170  readptr->current -= ntuples;
1171  return true;
1172  }
1173  Assert(!state->truncated);
1174  readptr->current = state->memtupdeleted;
1175  return false;
1176  }
1177  break;
1178 
1179  default:
1180  /* We don't currently try hard to optimize other cases */
1181  while (ntuples-- > 0)
1182  {
1183  void *tuple;
1184  bool should_free;
1185 
1186  tuple = tuplestore_gettuple(state, forward, &should_free);
1187 
1188  if (tuple == NULL)
1189  return false;
1190  if (should_free)
1191  pfree(tuple);
1193  }
1194  return true;
1195  }
1196 }
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122

References Assert(), CHECK_FOR_INTERRUPTS, TSReadPointer::current, TSReadPointer::eflags, TSReadPointer::eof_reached, EXEC_FLAG_BACKWARD, pfree(), TSS_INMEM, and tuplestore_gettuple().

Referenced by PersistHoldablePortal(), window_gettupleslot(), and WinSetMarkPosition().

◆ tuplestore_trim()

void tuplestore_trim ( Tuplestorestate state)

Definition at line 1360 of file tuplestore.c.

1361 {
1362  int oldest;
1363  int nremove;
1364  int i;
1365 
1366  /*
1367  * Truncation is disallowed if any read pointer requires rewind
1368  * capability.
1369  */
1370  if (state->eflags & EXEC_FLAG_REWIND)
1371  return;
1372 
1373  /*
1374  * We don't bother trimming temp files since it usually would mean more
1375  * work than just letting them sit in kernel buffers until they age out.
1376  */
1377  if (state->status != TSS_INMEM)
1378  return;
1379 
1380  /* Find the oldest read pointer */
1381  oldest = state->memtupcount;
1382  for (i = 0; i < state->readptrcount; i++)
1383  {
1384  if (!state->readptrs[i].eof_reached)
1385  oldest = Min(oldest, state->readptrs[i].current);
1386  }
1387 
1388  /*
1389  * Note: you might think we could remove all the tuples before the oldest
1390  * "current", since that one is the next to be returned. However, since
1391  * tuplestore_gettuple returns a direct pointer to our internal copy of
1392  * the tuple, it's likely that the caller has still got the tuple just
1393  * before "current" referenced in a slot. So we keep one extra tuple
1394  * before the oldest "current". (Strictly speaking, we could require such
1395  * callers to use the "copy" flag to tuplestore_gettupleslot, but for
1396  * efficiency we allow this one case to not use "copy".)
1397  */
1398  nremove = oldest - 1;
1399  if (nremove <= 0)
1400  return; /* nothing to do */
1401 
1402  Assert(nremove >= state->memtupdeleted);
1403  Assert(nremove <= state->memtupcount);
1404 
1405  /* Release no-longer-needed tuples */
1406  for (i = state->memtupdeleted; i < nremove; i++)
1407  {
1408  FREEMEM(state, GetMemoryChunkSpace(state->memtuples[i]));
1409  pfree(state->memtuples[i]);
1410  state->memtuples[i] = NULL;
1411  }
1412  state->memtupdeleted = nremove;
1413 
1414  /* mark tuplestore as truncated (used for Assert crosschecks only) */
1415  state->truncated = true;
1416 
1417  /*
1418  * If nremove is less than 1/8th memtupcount, just stop here, leaving the
1419  * "deleted" slots as NULL. This prevents us from expending O(N^2) time
1420  * repeatedly memmove-ing a large pointer array. The worst case space
1421  * wastage is pretty small, since it's just pointers and not whole tuples.
1422  */
1423  if (nremove < state->memtupcount / 8)
1424  return;
1425 
1426  /*
1427  * Slide the array down and readjust pointers.
1428  *
1429  * In mergejoin's current usage, it's demonstrable that there will always
1430  * be exactly one non-removed tuple; so optimize that case.
1431  */
1432  if (nremove + 1 == state->memtupcount)
1433  state->memtuples[0] = state->memtuples[nremove];
1434  else
1435  memmove(state->memtuples, state->memtuples + nremove,
1436  (state->memtupcount - nremove) * sizeof(void *));
1437 
1438  state->memtupdeleted = 0;
1439  state->memtupcount -= nremove;
1440  for (i = 0; i < state->readptrcount; i++)
1441  {
1442  if (!state->readptrs[i].eof_reached)
1443  state->readptrs[i].current -= nremove;
1444  }
1445 }
#define Min(x, y)
Definition: c.h:991

References Assert(), EXEC_FLAG_REWIND, FREEMEM, GetMemoryChunkSpace(), i, Min, pfree(), and TSS_INMEM.

Referenced by ExecMaterialMarkPos(), and ExecWindowAgg().

◆ tuplestore_tuple_count()

int64 tuplestore_tuple_count ( Tuplestorestate state)

Definition at line 546 of file tuplestore.c.

547 {
548  return state->tuples;
549 }

Referenced by exec_stmt_return_query(), fetch_remote_table_info(), and SPI_register_trigger_data().

◆ writetup_heap()

static void writetup_heap ( Tuplestorestate state,
void *  tup 
)
static

Definition at line 1500 of file tuplestore.c.

1501 {
1502  MinimalTuple tuple = (MinimalTuple) tup;
1503 
1504  /* the part of the MinimalTuple we'll write: */
1505  char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
1506  unsigned int tupbodylen = tuple->t_len - MINIMAL_TUPLE_DATA_OFFSET;
1507 
1508  /* total on-disk footprint: */
1509  unsigned int tuplen = tupbodylen + sizeof(int);
1510 
1511  BufFileWrite(state->myfile, &tuplen, sizeof(tuplen));
1512  BufFileWrite(state->myfile, tupbody, tupbodylen);
1513  if (state->backward) /* need trailing length word? */
1514  BufFileWrite(state->myfile, &tuplen, sizeof(tuplen));
1515 
1517  heap_free_minimal_tuple(tuple);
1518 }
void BufFileWrite(BufFile *file, const void *ptr, size_t size)
Definition: buffile.c:676
void heap_free_minimal_tuple(MinimalTuple mtup)
Definition: heaptuple.c:1523

References BufFileWrite(), FREEMEM, GetMemoryChunkSpace(), heap_free_minimal_tuple(), MINIMAL_TUPLE_DATA_OFFSET, and MinimalTupleData::t_len.

Referenced by tuplestore_begin_heap().