/* Private state */ typedefstruct
{
uint64 cutoff; /* select blocks with hash less than this */
uint32 seed; /* random seed */
BlockNumber nextblock; /* next block to consider sampling */
OffsetNumber lt; /* last tuple returned from current block */
} SystemSamplerData;
staticvoid system_samplescangetsamplesize(PlannerInfo *root,
RelOptInfo *baserel,
List *paramexprs,
BlockNumber *pages, double *tuples); staticvoid system_initsamplescan(SampleScanState *node, int eflags); staticvoid system_beginsamplescan(SampleScanState *node,
Datum *params, int nparams,
uint32 seed); static BlockNumber system_nextsampleblock(SampleScanState *node, BlockNumber nblocks); static OffsetNumber system_nextsampletuple(SampleScanState *node,
BlockNumber blockno,
OffsetNumber maxoffset);
/* *CreateaTsmRoutinedescriptorfortheSYSTEMmethod.
*/
Datum
tsm_system_handler(PG_FUNCTION_ARGS)
{
TsmRoutine *tsm = makeNode(TsmRoutine);
/* Try to extract an estimate for the sample percentage */
pctnode = (Node *) linitial(paramexprs);
pctnode = estimate_expression_value(root, pctnode);
if (IsA(pctnode, Const) &&
!((Const *) pctnode)->constisnull)
{
samplefract = DatumGetFloat4(((Const *) pctnode)->constvalue); if (samplefract >= 0 && samplefract <= 100 && !isnan(samplefract))
samplefract /= 100.0f; else
{ /* Default samplefract if the value is bogus */
samplefract = 0.1f;
}
} else
{ /* Default samplefract if we didn't obtain a non-null Const */
samplefract = 0.1f;
}
/* We'll visit a sample of the pages ... */
*pages = clamp_row_est(baserel->pages * samplefract);
/* ... and hopefully get a representative number of tuples from them */
*tuples = clamp_row_est(baserel->tuples * samplefract);
}
if (percent < 0 || percent > 100 || isnan(percent))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLESAMPLE_ARGUMENT),
errmsg("sample percentage must be between 0 and 100")));
if (nextblock < nblocks)
{ /* Found a suitable block; remember where we should start next time */
sampler->nextblock = nextblock + 1; return nextblock;
}
/* Done, but let's reset nextblock to 0 for safety. */
sampler->nextblock = 0; return InvalidBlockNumber;
}