PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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 "utils/tuplestore.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 void tuplestore_updatemax (Tuplestorestate *state)
 
static unsigned int getlen (Tuplestorestate *state, bool eofOK)
 
static voidcopytup_heap (Tuplestorestate *state, void *tup)
 
static void writetup_heap (Tuplestorestate *state, void *tup)
 
static voidreadtup_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 voidtuplestore_gettuple (Tuplestorestate *state, bool forward, bool *should_free)
 
bool tuplestore_gettupleslot (Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
 
bool tuplestore_gettupleslot_force (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)
 
void tuplestore_get_stats (Tuplestorestate *state, char **max_storage_type, int64 *max_space)
 
bool tuplestore_in_memory (Tuplestorestate *state)
 

Macro Definition Documentation

◆ COPYTUP

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

Definition at line 186 of file tuplestore.c.

◆ FREEMEM

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

Definition at line 191 of file tuplestore.c.

◆ LACKMEM

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

Definition at line 189 of file tuplestore.c.

◆ READTUP

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

Definition at line 188 of file tuplestore.c.

◆ USEMEM

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

Definition at line 190 of file tuplestore.c.

◆ WRITETUP

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

Definition at line 187 of file tuplestore.c.

Enumeration Type Documentation

◆ TupStoreStatus

Enumerator
TSS_INMEM 
TSS_WRITEFILE 
TSS_READFILE 

Definition at line 73 of file tuplestore.c.

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

Function Documentation

◆ copytup_heap()

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

Definition at line 1622 of file tuplestore.c.

1623{
1624 MinimalTuple tuple;
1625
1628 return tuple;
1629}
MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup, Size extra)
Definition heaptuple.c:1535
Size GetMemoryChunkSpace(void *pointer)
Definition mcxt.c:770
static int fb(int x)
#define USEMEM(state, amt)
Definition tuplestore.c:190

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

Referenced by tuplestore_begin_heap().

◆ dumptuples()

static void dumptuples ( Tuplestorestate state)
static

Definition at line 1291 of file tuplestore.c.

1292{
1293 int i;
1294
1295 for (i = state->memtupdeleted;; i++)
1296 {
1297 TSReadPointer *readptr = state->readptrs;
1298 int j;
1299
1300 for (j = 0; j < state->readptrcount; readptr++, j++)
1301 {
1302 if (i == readptr->current && !readptr->eof_reached)
1303 BufFileTell(state->myfile,
1304 &readptr->file, &readptr->offset);
1305 }
1306 if (i >= state->memtupcount)
1307 break;
1308 WRITETUP(state, state->memtuples[i]);
1309 }
1310 state->memtupdeleted = 0;
1311 state->memtupcount = 0;
1312}
void BufFileTell(BufFile *file, int *fileno, pgoff_t *offset)
Definition buffile.c:833
int j
Definition isn.c:78
int i
Definition isn.c:77
pgoff_t offset
Definition tuplestore.c:98
#define WRITETUP(state, tup)
Definition tuplestore.c:187

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 1598 of file tuplestore.c.

1599{
1600 unsigned int len;
1601 size_t nbytes;
1602
1603 nbytes = BufFileReadMaybeEOF(state->myfile, &len, sizeof(len), eofOK);
1604 if (nbytes == 0)
1605 return 0;
1606 else
1607 return len;
1608}
size_t BufFileReadMaybeEOF(BufFile *file, void *ptr, size_t size, bool eofOK)
Definition buffile.c:665
const void size_t len

References BufFileReadMaybeEOF(), fb(), and len.

Referenced by tuplestore_gettuple().

◆ grow_memtuples()

static bool grow_memtuples ( Tuplestorestate state)
static

Definition at line 613 of file tuplestore.c.

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

References elog, ERROR, fb(), 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 1653 of file tuplestore.c.

1654{
1655 unsigned int tupbodylen = len - sizeof(int);
1656 unsigned int tuplen = tupbodylen + MINIMAL_TUPLE_DATA_OFFSET;
1657 MinimalTuple tuple = (MinimalTuple) palloc(tuplen);
1658 char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
1659
1660 /* read in the tuple proper */
1661 tuple->t_len = tuplen;
1663 if (state->backward) /* need trailing length word? */
1664 BufFileReadExact(state->myfile, &tuplen, sizeof(tuplen));
1665 return tuple;
1666}
void BufFileReadExact(BufFile *file, void *ptr, size_t size)
Definition buffile.c:655
MinimalTupleData * MinimalTuple
Definition htup.h:27
#define MINIMAL_TUPLE_DATA_OFFSET
void * palloc(Size size)
Definition mcxt.c:1387

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

Referenced by tuplestore_begin_heap().

◆ tuplestore_advance()

bool tuplestore_advance ( Tuplestorestate state,
bool  forward 
)

Definition at line 1195 of file tuplestore.c.

1196{
1197 void *tuple;
1198 bool should_free;
1199
1201
1202 if (tuple)
1203 {
1204 if (should_free)
1205 pfree(tuple);
1206 return true;
1207 }
1208 else
1209 {
1210 return false;
1211 }
1212}
void pfree(void *pointer)
Definition mcxt.c:1616
static void * tuplestore_gettuple(Tuplestorestate *state, bool forward, bool *should_free)
Definition tuplestore.c:956

References fb(), 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 396 of file tuplestore.c.

397{
398 /* Check for possible increase of requirements */
399 if (state->status != TSS_INMEM || state->memtupcount != 0)
400 {
401 if ((state->eflags | eflags) != state->eflags)
402 elog(ERROR, "too late to require new tuplestore eflags");
403 }
404
405 /* Make room for another read pointer if needed */
406 if (state->readptrcount >= state->readptrsize)
407 {
408 int newcnt = state->readptrsize * 2;
409
410 state->readptrs = (TSReadPointer *)
411 repalloc(state->readptrs, newcnt * sizeof(TSReadPointer));
412 state->readptrsize = newcnt;
413 }
414
415 /* And set it up */
416 state->readptrs[state->readptrcount] = state->readptrs[0];
417 state->readptrs[state->readptrcount].eflags = eflags;
418
419 state->eflags |= eflags;
420
421 return state->readptrcount++;
422}
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632

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

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

◆ tuplestore_ateof()

bool tuplestore_ateof ( Tuplestorestate state)

Definition at line 592 of file tuplestore.c.

593{
594 return state->readptrs[state->activeptr].eof_reached;
595}

Referenced by CteScanNext(), and ExecMaterial().

◆ tuplestore_begin_common()

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

Definition at line 257 of file tuplestore.c.

258{
260
262
263 state->status = TSS_INMEM;
264 state->eflags = eflags;
265 state->interXact = interXact;
266 state->truncated = false;
267 state->usedDisk = false;
268 state->maxSpace = 0;
269 state->allowedMem = maxKBytes * (int64) 1024;
270 state->availMem = state->allowedMem;
271 state->myfile = NULL;
272
273 /*
274 * The palloc/pfree pattern for tuple memory is in a FIFO pattern. A
275 * generation context is perfectly suited for this.
276 */
278 "tuplestore tuples",
280 state->resowner = CurrentResourceOwner;
281
282 state->memtupdeleted = 0;
283 state->memtupcount = 0;
284 state->tuples = 0;
285
286 /*
287 * Initial size of array must be more than ALLOCSET_SEPARATE_THRESHOLD;
288 * see comments in grow_memtuples().
289 */
290 state->memtupsize = Max(16384 / sizeof(void *),
291 ALLOCSET_SEPARATE_THRESHOLD / sizeof(void *) + 1);
292
293 state->growmemtuples = true;
294 state->memtuples = (void **) palloc(state->memtupsize * sizeof(void *));
295
297
298 state->activeptr = 0;
299 state->readptrcount = 1;
300 state->readptrsize = 8; /* arbitrary */
301 state->readptrs = (TSReadPointer *)
302 palloc(state->readptrsize * sizeof(TSReadPointer));
303
304 state->readptrs[0].eflags = eflags;
305 state->readptrs[0].eof_reached = false;
306 state->readptrs[0].current = 0;
307
308 return state;
309}
#define Max(x, y)
Definition c.h:1087
#define palloc0_object(type)
Definition fe_memutils.h:75
MemoryContext GenerationContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition generation.c:162
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
#define ALLOCSET_SEPARATE_THRESHOLD
Definition memutils.h:187
ResourceOwner CurrentResourceOwner
Definition resowner.c:173

References ALLOCSET_DEFAULT_SIZES, ALLOCSET_SEPARATE_THRESHOLD, CurrentMemoryContext, CurrentResourceOwner, fb(), GenerationContextCreate(), GetMemoryChunkSpace(), Max, palloc(), palloc0_object, 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 331 of file tuplestore.c.

332{
334 int eflags;
335
336 /*
337 * This interpretation of the meaning of randomAccess is compatible with
338 * the pre-8.3 behavior of tuplestores.
339 */
340 eflags = randomAccess ?
343
344 state = tuplestore_begin_common(eflags, interXact, maxKBytes);
345
346 state->copytup = copytup_heap;
347 state->writetup = writetup_heap;
348 state->readtup = readtup_heap;
349
350 return state;
351}
#define EXEC_FLAG_BACKWARD
Definition executor.h:70
#define EXEC_FLAG_REWIND
Definition executor.h:69
static void writetup_heap(Tuplestorestate *state, void *tup)
static void * copytup_heap(Tuplestorestate *state, void *tup)
static Tuplestorestate * tuplestore_begin_common(int eflags, bool interXact, int maxKBytes)
Definition tuplestore.c:257
static void * readtup_heap(Tuplestorestate *state, unsigned int len)

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

Referenced by connectby(), crosstab(), exec_init_tuple_store(), ExecHashBuildNullTupleStore(), ExecInitCteScan(), ExecInitRecursiveUnion(), ExecMakeTableFunctionResult(), ExecMaterial(), get_crosstab_tuplestore(), GetCurrentFDWTuplestore(), InitMaterializedSRF(), libpqrcv_processTuples(), MakeTransitionCaptureState(), materializeQueryResult(), materializeResult(), plperl_return_next_internal(), pltcl_init_tuple_store(), populate_recordset_worker(), PortalCreateHoldStore(), postquel_start(), prepare_tuplestore(), storeRow(), and tfuncFetchRows().

◆ tuplestore_clear()

void tuplestore_clear ( Tuplestorestate state)

Definition at line 431 of file tuplestore.c.

432{
433 int i;
434 TSReadPointer *readptr;
435
436 /* update the maxSpace before doing any USEMEM/FREEMEM adjustments */
438
439 if (state->myfile)
440 BufFileClose(state->myfile);
441 state->myfile = NULL;
442
443#ifdef USE_ASSERT_CHECKING
444 {
445 int64 availMem = state->availMem;
446
447 /*
448 * Below, we reset the memory context for storing tuples. To save
449 * from having to always call GetMemoryChunkSpace() on all stored
450 * tuples, we adjust the availMem to forget all the tuples and just
451 * recall USEMEM for the space used by the memtuples array. Here we
452 * just Assert that's correct and the memory tracking hasn't gone
453 * wrong anywhere.
454 */
455 for (i = state->memtupdeleted; i < state->memtupcount; i++)
456 availMem += GetMemoryChunkSpace(state->memtuples[i]);
457
458 availMem += GetMemoryChunkSpace(state->memtuples);
459
460 Assert(availMem == state->allowedMem);
461 }
462#endif
463
464 /* clear the memory consumed by the memory tuples */
465 MemoryContextReset(state->context);
466
467 /*
468 * Zero the used memory and re-consume the space for the memtuples array.
469 * This saves having to FREEMEM for each stored tuple.
470 */
471 state->availMem = state->allowedMem;
473
474 state->status = TSS_INMEM;
475 state->truncated = false;
476 state->memtupdeleted = 0;
477 state->memtupcount = 0;
478 state->tuples = 0;
479 readptr = state->readptrs;
480 for (i = 0; i < state->readptrcount; readptr++, i++)
481 {
482 readptr->eof_reached = false;
483 readptr->current = 0;
484 }
485}
void BufFileClose(BufFile *file)
Definition buffile.c:413
#define Assert(condition)
Definition c.h:945
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
static void tuplestore_updatemax(Tuplestorestate *state)

References Assert, BufFileClose(), TSReadPointer::current, TSReadPointer::eof_reached, fb(), GetMemoryChunkSpace(), i, MemoryContextReset(), TSS_INMEM, tuplestore_updatemax(), and USEMEM.

Referenced by ExecRecursiveUnion(), ExecReScanCteScan(), ExecReScanRecursiveUnion(), and release_partition().

◆ tuplestore_copy_read_pointer()

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

Definition at line 1353 of file tuplestore.c.

1355{
1356 TSReadPointer *sptr = &state->readptrs[srcptr];
1357 TSReadPointer *dptr = &state->readptrs[destptr];
1358
1359 Assert(srcptr >= 0 && srcptr < state->readptrcount);
1360 Assert(destptr >= 0 && destptr < state->readptrcount);
1361
1362 /* Assigning to self is a no-op */
1363 if (srcptr == destptr)
1364 return;
1365
1366 if (dptr->eflags != sptr->eflags)
1367 {
1368 /* Possible change of overall eflags, so copy and then recompute */
1369 int eflags;
1370 int i;
1371
1372 *dptr = *sptr;
1373 eflags = state->readptrs[0].eflags;
1374 for (i = 1; i < state->readptrcount; i++)
1375 eflags |= state->readptrs[i].eflags;
1376 state->eflags = eflags;
1377 }
1378 else
1379 *dptr = *sptr;
1380
1381 switch (state->status)
1382 {
1383 case TSS_INMEM:
1384 case TSS_WRITEFILE:
1385 /* no work */
1386 break;
1387 case TSS_READFILE:
1388
1389 /*
1390 * This case is a bit tricky since the active read pointer's
1391 * position corresponds to the seek point, not what is in its
1392 * variables. Assigning to the active requires a seek, and
1393 * assigning from the active requires a tell, except when
1394 * eof_reached.
1395 */
1396 if (destptr == state->activeptr)
1397 {
1398 if (dptr->eof_reached)
1399 {
1400 if (BufFileSeek(state->myfile,
1401 state->writepos_file,
1402 state->writepos_offset,
1403 SEEK_SET) != 0)
1404 ereport(ERROR,
1406 errmsg("could not seek in tuplestore temporary file")));
1407 }
1408 else
1409 {
1410 if (BufFileSeek(state->myfile,
1411 dptr->file, dptr->offset,
1412 SEEK_SET) != 0)
1413 ereport(ERROR,
1415 errmsg("could not seek in tuplestore temporary file")));
1416 }
1417 }
1418 else if (srcptr == state->activeptr)
1419 {
1420 if (!dptr->eof_reached)
1421 BufFileTell(state->myfile,
1422 &dptr->file,
1423 &dptr->offset);
1424 }
1425 break;
1426 default:
1427 elog(ERROR, "invalid tuplestore state");
1428 break;
1429 }
1430}
int BufFileSeek(BufFile *file, int fileno, pgoff_t offset, int whence)
Definition buffile.c:741
int errcode_for_file_access(void)
Definition elog.c:897
#define ereport(elevel,...)
Definition elog.h:150
static char * errmsg

References Assert, BufFileSeek(), BufFileTell(), elog, ereport, errcode_for_file_access(), errmsg, ERROR, fb(), i, TSS_INMEM, TSS_READFILE, and TSS_WRITEFILE.

Referenced by ExecMaterialMarkPos(), and ExecMaterialRestrPos().

◆ tuplestore_end()

◆ tuplestore_get_stats()

void tuplestore_get_stats ( Tuplestorestate state,
char **  max_storage_type,
int64 max_space 
)

Definition at line 1566 of file tuplestore.c.

1568{
1570
1571 if (state->usedDisk)
1572 *max_storage_type = "Disk";
1573 else
1574 *max_storage_type = "Memory";
1575
1576 *max_space = state->maxSpace;
1577}

References fb(), and tuplestore_updatemax().

Referenced by show_ctescan_info(), show_material_info(), show_recursive_union_info(), show_table_func_scan_info(), and show_windowagg_info().

◆ tuplestore_gettuple()

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

Definition at line 956 of file tuplestore.c.

958{
959 TSReadPointer *readptr = &state->readptrs[state->activeptr];
960 unsigned int tuplen;
961 void *tup;
962
963 Assert(forward || (readptr->eflags & EXEC_FLAG_BACKWARD));
964
965 switch (state->status)
966 {
967 case TSS_INMEM:
968 *should_free = false;
969 if (forward)
970 {
971 if (readptr->eof_reached)
972 return NULL;
973 if (readptr->current < state->memtupcount)
974 {
975 /* We have another tuple, so return it */
976 return state->memtuples[readptr->current++];
977 }
978 readptr->eof_reached = true;
979 return NULL;
980 }
981 else
982 {
983 /*
984 * if all tuples are fetched already then we return last
985 * tuple, else tuple before last returned.
986 */
987 if (readptr->eof_reached)
988 {
989 readptr->current = state->memtupcount;
990 readptr->eof_reached = false;
991 }
992 else
993 {
994 if (readptr->current <= state->memtupdeleted)
995 {
996 Assert(!state->truncated);
997 return NULL;
998 }
999 readptr->current--; /* last returned tuple */
1000 }
1001 if (readptr->current <= state->memtupdeleted)
1002 {
1003 Assert(!state->truncated);
1004 return NULL;
1005 }
1006 return state->memtuples[readptr->current - 1];
1007 }
1008 break;
1009
1010 case TSS_WRITEFILE:
1011 /* Skip state change if we'll just return NULL */
1012 if (readptr->eof_reached && forward)
1013 return NULL;
1014
1015 /*
1016 * Switch from writing to reading.
1017 */
1018 BufFileTell(state->myfile,
1019 &state->writepos_file, &state->writepos_offset);
1020 if (!readptr->eof_reached)
1021 if (BufFileSeek(state->myfile,
1022 readptr->file, readptr->offset,
1023 SEEK_SET) != 0)
1024 ereport(ERROR,
1026 errmsg("could not seek in tuplestore temporary file")));
1027 state->status = TSS_READFILE;
1029
1030 case TSS_READFILE:
1031 *should_free = true;
1032 if (forward)
1033 {
1034 if ((tuplen = getlen(state, true)) != 0)
1035 {
1036 tup = READTUP(state, tuplen);
1037 return tup;
1038 }
1039 else
1040 {
1041 readptr->eof_reached = true;
1042 return NULL;
1043 }
1044 }
1045
1046 /*
1047 * Backward.
1048 *
1049 * if all tuples are fetched already then we return last tuple,
1050 * else tuple before last returned.
1051 *
1052 * Back up to fetch previously-returned tuple's ending length
1053 * word. If seek fails, assume we are at start of file.
1054 */
1055 if (BufFileSeek(state->myfile, 0, -(pgoff_t) sizeof(unsigned int),
1056 SEEK_CUR) != 0)
1057 {
1058 /* even a failed backwards fetch gets you out of eof state */
1059 readptr->eof_reached = false;
1060 Assert(!state->truncated);
1061 return NULL;
1062 }
1063 tuplen = getlen(state, false);
1064
1065 if (readptr->eof_reached)
1066 {
1067 readptr->eof_reached = false;
1068 /* We will return the tuple returned before returning NULL */
1069 }
1070 else
1071 {
1072 /*
1073 * Back up to get ending length word of tuple before it.
1074 */
1075 if (BufFileSeek(state->myfile, 0,
1076 -(pgoff_t) (tuplen + 2 * sizeof(unsigned int)),
1077 SEEK_CUR) != 0)
1078 {
1079 /*
1080 * If that fails, presumably the prev tuple is the first
1081 * in the file. Back up so that it becomes next to read
1082 * in forward direction (not obviously right, but that is
1083 * what in-memory case does).
1084 */
1085 if (BufFileSeek(state->myfile, 0,
1086 -(pgoff_t) (tuplen + sizeof(unsigned int)),
1087 SEEK_CUR) != 0)
1088 ereport(ERROR,
1090 errmsg("could not seek in tuplestore temporary file")));
1091 Assert(!state->truncated);
1092 return NULL;
1093 }
1094 tuplen = getlen(state, false);
1095 }
1096
1097 /*
1098 * Now we have the length of the prior tuple, back up and read it.
1099 * Note: READTUP expects we are positioned after the initial
1100 * length word of the tuple, so back up to that point.
1101 */
1102 if (BufFileSeek(state->myfile, 0,
1103 -(pgoff_t) tuplen,
1104 SEEK_CUR) != 0)
1105 ereport(ERROR,
1107 errmsg("could not seek in tuplestore temporary file")));
1108 tup = READTUP(state, tuplen);
1109 return tup;
1110
1111 default:
1112 elog(ERROR, "invalid tuplestore state");
1113 return NULL; /* keep compiler quiet */
1114 }
1115}
#define pg_fallthrough
Definition c.h:152
off_t pgoff_t
Definition port.h:421
#define READTUP(state, len)
Definition tuplestore.c:188
static unsigned int getlen(Tuplestorestate *state, bool eofOK)

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

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

◆ tuplestore_gettupleslot()

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

Definition at line 1131 of file tuplestore.c.

1133{
1134 MinimalTuple tuple;
1135 bool should_free;
1136
1138
1139 if (tuple)
1140 {
1141 if (copy && !should_free)
1142 {
1143 tuple = heap_copy_minimal_tuple(tuple, 0);
1144 should_free = true;
1145 }
1146 ExecStoreMinimalTuple(tuple, slot, should_free);
1147 return true;
1148 }
1149 else
1150 {
1151 ExecClearTuple(slot);
1152 return false;
1153 }
1154}
TupleTableSlot * ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)
MinimalTuple heap_copy_minimal_tuple(MinimalTuple mtup, Size extra)
Definition heaptuple.c:1490
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:476

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

Referenced by AfterTriggerExecute(), check_pub_dead_tuple_retention(), check_publications(), check_publications_origin_sequences(), check_publications_origin_tables(), copy_sequences(), CteScanNext(), ExecHashJoinImpl(), ExecMakeFunctionResultSet(), ExecMaterial(), ExecWindowAgg(), fetch_relation_list(), fetch_remote_slots(), fetch_remote_table_info(), FunctionNext(), NamedTuplestoreScanNext(), RunFromStore(), TableFuncNext(), update_frameheadpos(), update_frametailpos(), update_grouptailpos(), validate_remote_info(), window_gettupleslot(), and WorkTableScanNext().

◆ tuplestore_gettupleslot_force()

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

Definition at line 1163 of file tuplestore.c.

1165{
1166 MinimalTuple tuple;
1167 bool should_free;
1168
1170
1171 if (tuple)
1172 {
1173 if (copy && !should_free)
1174 {
1175 tuple = heap_copy_minimal_tuple(tuple, 0);
1176 should_free = true;
1177 }
1179 return true;
1180 }
1181 else
1182 {
1183 ExecClearTuple(slot);
1184 return false;
1185 }
1186}
void ExecForceStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree)

References ExecClearTuple(), ExecForceStoreMinimalTuple(), fb(), heap_copy_minimal_tuple(), and tuplestore_gettuple().

Referenced by ExecHashJoinImpl().

◆ tuplestore_in_memory()

bool tuplestore_in_memory ( Tuplestorestate state)

Definition at line 1587 of file tuplestore.c.

1588{
1589 return (state->status == TSS_INMEM);
1590}

References TSS_INMEM.

Referenced by spool_tuples().

◆ tuplestore_puttuple()

void tuplestore_puttuple ( Tuplestorestate state,
HeapTuple  tuple 
)

Definition at line 765 of file tuplestore.c.

766{
768
769 /*
770 * Copy the tuple. (Must do this even in WRITEFILE case. Note that
771 * COPYTUP includes USEMEM, so we needn't do that here.)
772 */
773 tuple = COPYTUP(state, tuple);
774
776
778}
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
#define COPYTUP(state, tup)
Definition tuplestore.c:186
static void tuplestore_puttuple_common(Tuplestorestate *state, void *tuple)
Definition tuplestore.c:800

References COPYTUP, fb(), 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(), materializeQueryResult(), 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 800 of file tuplestore.c.

801{
802 TSReadPointer *readptr;
803 int i;
804 ResourceOwner oldowner;
806
807 state->tuples++;
808
809 switch (state->status)
810 {
811 case TSS_INMEM:
812
813 /*
814 * Update read pointers as needed; see API spec above.
815 */
816 readptr = state->readptrs;
817 for (i = 0; i < state->readptrcount; readptr++, i++)
818 {
819 if (readptr->eof_reached && i != state->activeptr)
820 {
821 readptr->eof_reached = false;
822 readptr->current = state->memtupcount;
823 }
824 }
825
826 /*
827 * Grow the array as needed. Note that we try to grow the array
828 * when there is still one free slot remaining --- if we fail,
829 * there'll still be room to store the incoming tuple, and then
830 * we'll switch to tape-based operation.
831 */
832 if (state->memtupcount >= state->memtupsize - 1)
833 {
835 Assert(state->memtupcount < state->memtupsize);
836 }
837
838 /* Stash the tuple in the in-memory array */
839 state->memtuples[state->memtupcount++] = tuple;
840
841 /*
842 * Done if we still fit in available memory and have array slots.
843 */
844 if (state->memtupcount < state->memtupsize && !LACKMEM(state))
845 return;
846
847 /*
848 * Nope; time to switch to tape-based operation. Make sure that
849 * the temp file(s) are created in suitable temp tablespaces.
850 */
852
853 /* associate the file with the store's resource owner */
854 oldowner = CurrentResourceOwner;
855 CurrentResourceOwner = state->resowner;
856
857 /*
858 * We switch out of the state->context as this is a generation
859 * context, which isn't ideal for allocations relating to the
860 * BufFile.
861 */
862 oldcxt = MemoryContextSwitchTo(state->context->parent);
863
864 state->myfile = BufFileCreateTemp(state->interXact);
865
867
868 CurrentResourceOwner = oldowner;
869
870 /*
871 * Freeze the decision about whether trailing length words will be
872 * used. We can't change this choice once data is on tape, even
873 * though callers might drop the requirement.
874 */
875 state->backward = (state->eflags & EXEC_FLAG_BACKWARD) != 0;
876
877 /*
878 * Update the maximum space used before dumping the tuples. It's
879 * possible that more space will be used by the tuples in memory
880 * than the space that will be used on disk.
881 */
883
884 state->status = TSS_WRITEFILE;
886 break;
887 case TSS_WRITEFILE:
888
889 /*
890 * Update read pointers as needed; see API spec above. Note:
891 * BufFileTell is quite cheap, so not worth trying to avoid
892 * multiple calls.
893 */
894 readptr = state->readptrs;
895 for (i = 0; i < state->readptrcount; readptr++, i++)
896 {
897 if (readptr->eof_reached && i != state->activeptr)
898 {
899 readptr->eof_reached = false;
900 BufFileTell(state->myfile,
901 &readptr->file,
902 &readptr->offset);
903 }
904 }
905
906 WRITETUP(state, tuple);
907 break;
908 case TSS_READFILE:
909
910 /*
911 * Switch from reading to writing.
912 */
913 if (!state->readptrs[state->activeptr].eof_reached)
914 BufFileTell(state->myfile,
915 &state->readptrs[state->activeptr].file,
916 &state->readptrs[state->activeptr].offset);
917 if (BufFileSeek(state->myfile,
918 state->writepos_file, state->writepos_offset,
919 SEEK_SET) != 0)
922 errmsg("could not seek in tuplestore temporary file")));
923 state->status = TSS_WRITEFILE;
924
925 /*
926 * Update read pointers as needed; see API spec above.
927 */
928 readptr = state->readptrs;
929 for (i = 0; i < state->readptrcount; readptr++, i++)
930 {
931 if (readptr->eof_reached && i != state->activeptr)
932 {
933 readptr->eof_reached = false;
934 readptr->file = state->writepos_file;
935 readptr->offset = state->writepos_offset;
936 }
937 }
938
939 WRITETUP(state, tuple);
940 break;
941 default:
942 elog(ERROR, "invalid tuplestore state");
943 break;
944 }
945}
void PrepareTempTablespaces(void)
BufFile * BufFileCreateTemp(bool interXact)
Definition buffile.c:194
static bool grow_memtuples(Tuplestorestate *state)
Definition tuplestore.c:613
static void dumptuples(Tuplestorestate *state)

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

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

◆ tuplestore_puttupleslot()

◆ tuplestore_putvalues()

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

Definition at line 785 of file tuplestore.c.

787{
788 MinimalTuple tuple;
790
791 tuple = heap_form_minimal_tuple(tdesc, values, isnull, 0);
793
795
797}
static Datum values[MAXATTR]
Definition bootstrap.c:188
MinimalTuple heap_form_minimal_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull, Size extra)
Definition heaptuple.c:1402

References fb(), 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(), injection_points_list(), LogicalOutputWrite(), pg_available_extensions(), pg_buffercache_usage_counts(), pg_config(), pg_cursor(), pg_event_trigger_ddl_commands(), pg_event_trigger_dropped_objects(), pg_extension_update_paths(), pg_get_aios(), pg_get_dsm_registry_allocations(), pg_get_loaded_modules(), pg_get_replication_slots(), pg_get_shmem_allocations(), pg_get_shmem_allocations_numa(), pg_get_wait_events(), pg_get_wal_resource_managers(), pg_ls_dir(), pg_ls_dir_files(), pg_options_to_table(), pg_prepared_statement(), pg_show_replication_origin_status(), pg_stat_get_activity(), 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_io_build_tuples(), pg_stat_statements_internal(), pg_tablespace_databases(), pg_timezone_names(), plperl_return_next_internal(), pltcl_returnnext(), postgres_fdw_get_connections_internal(), PutMemoryContextsStatsTupleStore(), show_all_file_settings(), split_text_accum_result(), tfuncLoadRows(), and tstoreReceiveSlot_detoast().

◆ tuplestore_rescan()

void tuplestore_rescan ( Tuplestorestate state)

Definition at line 1318 of file tuplestore.c.

1319{
1320 TSReadPointer *readptr = &state->readptrs[state->activeptr];
1321
1322 Assert(readptr->eflags & EXEC_FLAG_REWIND);
1323 Assert(!state->truncated);
1324
1325 switch (state->status)
1326 {
1327 case TSS_INMEM:
1328 readptr->eof_reached = false;
1329 readptr->current = 0;
1330 break;
1331 case TSS_WRITEFILE:
1332 readptr->eof_reached = false;
1333 readptr->file = 0;
1334 readptr->offset = 0;
1335 break;
1336 case TSS_READFILE:
1337 readptr->eof_reached = false;
1338 if (BufFileSeek(state->myfile, 0, 0, SEEK_SET) != 0)
1339 ereport(ERROR,
1341 errmsg("could not seek in tuplestore temporary file")));
1342 break;
1343 default:
1344 elog(ERROR, "invalid tuplestore state");
1345 break;
1346 }
1347}

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

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

◆ tuplestore_select_read_pointer()

void tuplestore_select_read_pointer ( Tuplestorestate state,
int  ptr 
)

Definition at line 508 of file tuplestore.c.

509{
510 TSReadPointer *readptr;
512
513 Assert(ptr >= 0 && ptr < state->readptrcount);
514
515 /* No work if already active */
516 if (ptr == state->activeptr)
517 return;
518
519 readptr = &state->readptrs[ptr];
520 oldptr = &state->readptrs[state->activeptr];
521
522 switch (state->status)
523 {
524 case TSS_INMEM:
525 case TSS_WRITEFILE:
526 /* no work */
527 break;
528 case TSS_READFILE:
529
530 /*
531 * First, save the current read position in the pointer about to
532 * become inactive.
533 */
534 if (!oldptr->eof_reached)
535 BufFileTell(state->myfile,
536 &oldptr->file,
537 &oldptr->offset);
538
539 /*
540 * We have to make the temp file's seek position equal to the
541 * logical position of the new read pointer. In eof_reached
542 * state, that's the EOF, which we have available from the saved
543 * write position.
544 */
545 if (readptr->eof_reached)
546 {
547 if (BufFileSeek(state->myfile,
548 state->writepos_file,
549 state->writepos_offset,
550 SEEK_SET) != 0)
553 errmsg("could not seek in tuplestore temporary file")));
554 }
555 else
556 {
557 if (BufFileSeek(state->myfile,
558 readptr->file,
559 readptr->offset,
560 SEEK_SET) != 0)
563 errmsg("could not seek in tuplestore temporary file")));
564 }
565 break;
566 default:
567 elog(ERROR, "invalid tuplestore state");
568 break;
569 }
570
571 state->activeptr = ptr;
572}

References Assert, BufFileSeek(), BufFileTell(), elog, TSReadPointer::eof_reached, ereport, errcode_for_file_access(), errmsg, ERROR, fb(), 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 372 of file tuplestore.c.

373{
374 int i;
375
376 if (state->status != TSS_INMEM || state->memtupcount != 0)
377 elog(ERROR, "too late to call tuplestore_set_eflags");
378
379 state->readptrs[0].eflags = eflags;
380 for (i = 1; i < state->readptrcount; i++)
381 eflags |= state->readptrs[i].eflags;
382 state->eflags = eflags;
383}

References elog, ERROR, i, and TSS_INMEM.

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

◆ tuplestore_skiptuples()

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

Definition at line 1220 of file tuplestore.c.

1221{
1222 TSReadPointer *readptr = &state->readptrs[state->activeptr];
1223
1224 Assert(forward || (readptr->eflags & EXEC_FLAG_BACKWARD));
1225
1226 if (ntuples <= 0)
1227 return true;
1228
1229 switch (state->status)
1230 {
1231 case TSS_INMEM:
1232 if (forward)
1233 {
1234 if (readptr->eof_reached)
1235 return false;
1236 if (state->memtupcount - readptr->current >= ntuples)
1237 {
1238 readptr->current += ntuples;
1239 return true;
1240 }
1241 readptr->current = state->memtupcount;
1242 readptr->eof_reached = true;
1243 return false;
1244 }
1245 else
1246 {
1247 if (readptr->eof_reached)
1248 {
1249 readptr->current = state->memtupcount;
1250 readptr->eof_reached = false;
1251 ntuples--;
1252 }
1253 if (readptr->current - state->memtupdeleted > ntuples)
1254 {
1255 readptr->current -= ntuples;
1256 return true;
1257 }
1258 Assert(!state->truncated);
1259 readptr->current = state->memtupdeleted;
1260 return false;
1261 }
1262 break;
1263
1264 default:
1265 /* We don't currently try hard to optimize other cases */
1266 while (ntuples-- > 0)
1267 {
1268 void *tuple;
1269 bool should_free;
1270
1272
1273 if (tuple == NULL)
1274 return false;
1275 if (should_free)
1276 pfree(tuple);
1278 }
1279 return true;
1280 }
1281}
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123

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

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

◆ tuplestore_trim()

void tuplestore_trim ( Tuplestorestate state)

Definition at line 1445 of file tuplestore.c.

1446{
1447 int oldest;
1448 int nremove;
1449 int i;
1450
1451 /*
1452 * Truncation is disallowed if any read pointer requires rewind
1453 * capability.
1454 */
1455 if (state->eflags & EXEC_FLAG_REWIND)
1456 return;
1457
1458 /*
1459 * We don't bother trimming temp files since it usually would mean more
1460 * work than just letting them sit in kernel buffers until they age out.
1461 */
1462 if (state->status != TSS_INMEM)
1463 return;
1464
1465 /* Find the oldest read pointer */
1466 oldest = state->memtupcount;
1467 for (i = 0; i < state->readptrcount; i++)
1468 {
1469 if (!state->readptrs[i].eof_reached)
1470 oldest = Min(oldest, state->readptrs[i].current);
1471 }
1472
1473 /*
1474 * Note: you might think we could remove all the tuples before the oldest
1475 * "current", since that one is the next to be returned. However, since
1476 * tuplestore_gettuple returns a direct pointer to our internal copy of
1477 * the tuple, it's likely that the caller has still got the tuple just
1478 * before "current" referenced in a slot. So we keep one extra tuple
1479 * before the oldest "current". (Strictly speaking, we could require such
1480 * callers to use the "copy" flag to tuplestore_gettupleslot, but for
1481 * efficiency we allow this one case to not use "copy".)
1482 */
1483 nremove = oldest - 1;
1484 if (nremove <= 0)
1485 return; /* nothing to do */
1486
1487 Assert(nremove >= state->memtupdeleted);
1488 Assert(nremove <= state->memtupcount);
1489
1490 /* before freeing any memory, update the statistics */
1492
1493 /* Release no-longer-needed tuples */
1494 for (i = state->memtupdeleted; i < nremove; i++)
1495 {
1496 FREEMEM(state, GetMemoryChunkSpace(state->memtuples[i]));
1497 pfree(state->memtuples[i]);
1498 state->memtuples[i] = NULL;
1499 }
1500 state->memtupdeleted = nremove;
1501
1502 /* mark tuplestore as truncated (used for Assert crosschecks only) */
1503 state->truncated = true;
1504
1505 /*
1506 * If nremove is less than 1/8th memtupcount, just stop here, leaving the
1507 * "deleted" slots as NULL. This prevents us from expending O(N^2) time
1508 * repeatedly memmove-ing a large pointer array. The worst case space
1509 * wastage is pretty small, since it's just pointers and not whole tuples.
1510 */
1511 if (nremove < state->memtupcount / 8)
1512 return;
1513
1514 /*
1515 * Slide the array down and readjust pointers.
1516 *
1517 * In mergejoin's current usage, it's demonstrable that there will always
1518 * be exactly one non-removed tuple; so optimize that case.
1519 */
1520 if (nremove + 1 == state->memtupcount)
1521 state->memtuples[0] = state->memtuples[nremove];
1522 else
1523 memmove(state->memtuples, state->memtuples + nremove,
1524 (state->memtupcount - nremove) * sizeof(void *));
1525
1526 state->memtupdeleted = 0;
1527 state->memtupcount -= nremove;
1528 for (i = 0; i < state->readptrcount; i++)
1529 {
1530 if (!state->readptrs[i].eof_reached)
1531 state->readptrs[i].current -= nremove;
1532 }
1533}
#define Min(x, y)
Definition c.h:1093

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

Referenced by ExecMaterialMarkPos(), and ExecWindowAgg().

◆ tuplestore_tuple_count()

int64 tuplestore_tuple_count ( Tuplestorestate state)

Definition at line 581 of file tuplestore.c.

582{
583 return state->tuples;
584}

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

◆ tuplestore_updatemax()

static void tuplestore_updatemax ( Tuplestorestate state)
static

Definition at line 1541 of file tuplestore.c.

1542{
1543 if (state->status == TSS_INMEM)
1544 state->maxSpace = Max(state->maxSpace,
1545 state->allowedMem - state->availMem);
1546 else
1547 {
1548 state->maxSpace = Max(state->maxSpace,
1549 BufFileSize(state->myfile));
1550
1551 /*
1552 * usedDisk never gets set to false again after spilling to disk, even
1553 * if tuplestore_clear() is called and new tuples go to memory again.
1554 */
1555 state->usedDisk = true;
1556 }
1557}
int64 BufFileSize(BufFile *file)
Definition buffile.c:866

References BufFileSize(), Max, and TSS_INMEM.

Referenced by tuplestore_clear(), tuplestore_get_stats(), tuplestore_puttuple_common(), and tuplestore_trim().

◆ writetup_heap()

static void writetup_heap ( Tuplestorestate state,
void tup 
)
static

Definition at line 1632 of file tuplestore.c.

1633{
1634 MinimalTuple tuple = (MinimalTuple) tup;
1635
1636 /* the part of the MinimalTuple we'll write: */
1637 char *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
1638 unsigned int tupbodylen = tuple->t_len - MINIMAL_TUPLE_DATA_OFFSET;
1639
1640 /* total on-disk footprint: */
1641 unsigned int tuplen = tupbodylen + sizeof(int);
1642
1643 BufFileWrite(state->myfile, &tuplen, sizeof(tuplen));
1645 if (state->backward) /* need trailing length word? */
1646 BufFileWrite(state->myfile, &tuplen, sizeof(tuplen));
1647
1650}
void BufFileWrite(BufFile *file, const void *ptr, size_t size)
Definition buffile.c:677
void heap_free_minimal_tuple(MinimalTuple mtup)
Definition heaptuple.c:1478

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

Referenced by tuplestore_begin_heap().