mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
tableam: sample scan.
This moves sample scan support to below tableam. It's not optional as there is, in contrast to e.g. bitmap heap scans, no alternative way to perform tablesample queries. If an AM can't deal with the block based API, it will have to throw an ERROR. The tableam callbacks for this are block based, but given the current TsmRoutine interface, that seems to be required. The new interface doesn't require TsmRoutines to perform visibility checks anymore - that requires the TsmRoutine to know details about the AM, which we want to avoid. To continue to allow taking the returned number of tuples account SampleScanState now has a donetuples field (which previously e.g. existed in SystemRowsSamplerData), which is only incremented after the visibility check succeeds. Author: Andres Freund Discussion: https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
This commit is contained in:
@@ -30,6 +30,7 @@ extern bool synchronize_seqscans;
|
||||
struct BulkInsertStateData;
|
||||
struct IndexInfo;
|
||||
struct IndexBuildCallback;
|
||||
struct SampleScanState;
|
||||
struct VacuumParams;
|
||||
struct ValidateIndexState;
|
||||
|
||||
@@ -519,6 +520,56 @@ typedef struct TableAmRoutine
|
||||
BlockNumber *pages, double *tuples,
|
||||
double *allvisfrac);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Executor related functions.
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Acquire the next block in a sample scan. Return false if the sample
|
||||
* scan is finished, true otherwise.
|
||||
*
|
||||
* Typically this will first determine the target block by call the
|
||||
* TsmRoutine's NextSampleBlock() callback if not NULL, or alternatively
|
||||
* perform a sequential scan over all blocks. The determined block is
|
||||
* then typically read and pinned.
|
||||
*
|
||||
* As the TsmRoutine interface is block based, a block needs to be passed
|
||||
* to NextSampleBlock(). If that's not appropriate for an AM, it
|
||||
* internally needs to perform mapping between the internal and a block
|
||||
* based representation.
|
||||
*
|
||||
* Note that it's not acceptable to hold deadlock prone resources such as
|
||||
* lwlocks until scan_sample_next_tuple() has exhausted the tuples on the
|
||||
* block - the tuple is likely to be returned to an upper query node, and
|
||||
* the next call could be off a long while. Holding buffer pins etc is
|
||||
* obviously OK.
|
||||
*
|
||||
* Currently it is required to implement this interface, as there's no
|
||||
* alternative way (contrary e.g. to bitmap scans) to implement sample
|
||||
* scans. If infeasible to implement the AM may raise an error.
|
||||
*/
|
||||
bool (*scan_sample_next_block) (TableScanDesc scan,
|
||||
struct SampleScanState *scanstate);
|
||||
|
||||
/*
|
||||
* This callback, only called after scan_sample_next_block has returned
|
||||
* true, should determine the next tuple to be returned from the selected
|
||||
* block using the TsmRoutine's NextSampleTuple() callback.
|
||||
*
|
||||
* The callback needs to perform visibility checks, and only return
|
||||
* visible tuples. That obviously can mean calling NextSampletuple()
|
||||
* multiple times.
|
||||
*
|
||||
* The TsmRoutine interface assumes that there's a maximum offset on a
|
||||
* given page, so if that doesn't apply to an AM, it needs to emulate that
|
||||
* assumption somehow.
|
||||
*/
|
||||
bool (*scan_sample_next_tuple) (TableScanDesc scan,
|
||||
struct SampleScanState *scanstate,
|
||||
TupleTableSlot *slot);
|
||||
|
||||
} TableAmRoutine;
|
||||
|
||||
|
||||
@@ -1339,6 +1390,43 @@ table_relation_estimate_size(Relation rel, int32 *attr_widths,
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Executor related functionality
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Acquire the next block in a sample scan. Returns false if the sample scan
|
||||
* is finished, true otherwise.
|
||||
*
|
||||
* This will call the TsmRoutine's NextSampleBlock() callback if necessary
|
||||
* (i.e. NextSampleBlock is not NULL), or perform a sequential scan over the
|
||||
* underlying relation.
|
||||
*/
|
||||
static inline bool
|
||||
table_scan_sample_next_block(TableScanDesc scan,
|
||||
struct SampleScanState *scanstate)
|
||||
{
|
||||
return scan->rs_rd->rd_tableam->scan_sample_next_block(scan, scanstate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch the next sample tuple into `slot` and return true if a visible tuple
|
||||
* was found, false otherwise. table_scan_sample_next_block() needs to
|
||||
* previously have selected a block (i.e. returned true).
|
||||
*
|
||||
* This will call the TsmRoutine's NextSampleTuple() callback.
|
||||
*/
|
||||
static inline bool
|
||||
table_scan_sample_next_tuple(TableScanDesc scan,
|
||||
struct SampleScanState *scanstate,
|
||||
TupleTableSlot *slot)
|
||||
{
|
||||
return scan->rs_rd->rd_tableam->scan_sample_next_tuple(scan, scanstate,
|
||||
slot);
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Functions to make modifications a bit simpler.
|
||||
* ----------------------------------------------------------------------------
|
||||
|
@@ -34,7 +34,8 @@ typedef void (*BeginSampleScan_function) (SampleScanState *node,
|
||||
int nparams,
|
||||
uint32 seed);
|
||||
|
||||
typedef BlockNumber (*NextSampleBlock_function) (SampleScanState *node);
|
||||
typedef BlockNumber (*NextSampleBlock_function) (SampleScanState *node,
|
||||
BlockNumber nblocks);
|
||||
|
||||
typedef OffsetNumber (*NextSampleTuple_function) (SampleScanState *node,
|
||||
BlockNumber blockno,
|
||||
|
@@ -1305,6 +1305,9 @@ typedef struct SampleScanState
|
||||
bool use_pagemode; /* use page-at-a-time visibility checking? */
|
||||
bool begun; /* false means need to call BeginSampleScan */
|
||||
uint32 seed; /* random seed */
|
||||
int64 donetuples; /* number of tuples already returned */
|
||||
bool haveblock; /* has a block for sampling been determined */
|
||||
bool done; /* exhausted all tuples? */
|
||||
} SampleScanState;
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user