1 /*-------------------------------------------------------------------------
4 * Support routines for sample scans of relations (table sampling).
6 * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/executor/nodeSamplescan.c
13 *-------------------------------------------------------------------------
17 #include "access/tablesample.h"
18 #include "executor/executor.h"
19 #include "executor/nodeSamplescan.h"
20 #include "miscadmin.h"
21 #include "parser/parsetree.h"
23 #include "storage/bufmgr.h"
24 #include "storage/predicate.h"
25 #include "utils/rel.h"
26 #include "utils/syscache.h"
27 #include "utils/tqual.h"
29 static void InitScanRelation(SampleScanState *node, EState *estate,
30 int eflags, TableSampleClause *tablesample);
31 static TupleTableSlot *SampleNext(SampleScanState *node);
34 /* ----------------------------------------------------------------
36 * ----------------------------------------------------------------
39 /* ----------------------------------------------------------------
42 * This is a workhorse for ExecSampleScan
43 * ----------------------------------------------------------------
45 static TupleTableSlot *
46 SampleNext(SampleScanState *node)
49 TableSampleDesc *tsdesc;
53 * get information from the scan state
55 slot = node->ss.ss_ScanTupleSlot;
56 tsdesc = node->tsdesc;
58 tuple = tablesample_getnext(tsdesc);
61 ExecStoreTuple(tuple, /* tuple to store */
62 slot, /* slot to store in */
63 tsdesc->heapScan->rs_cbuf, /* buffer associated
65 false); /* don't pfree this pointer */
73 * SampleRecheck -- access method routine to recheck a tuple in EvalPlanQual
76 SampleRecheck(SampleScanState *node, TupleTableSlot *slot)
78 /* No need to recheck for SampleScan */
82 /* ----------------------------------------------------------------
83 * ExecSampleScan(node)
85 * Scans the relation using the sampling method and returns
86 * the next qualifying tuple.
87 * We call the ExecScan() routine and pass it the appropriate
88 * access method functions.
89 * ----------------------------------------------------------------
92 ExecSampleScan(SampleScanState *node)
94 return ExecScan((ScanState *) node,
95 (ExecScanAccessMtd) SampleNext,
96 (ExecScanRecheckMtd) SampleRecheck);
99 /* ----------------------------------------------------------------
102 * Set up to access the scan relation.
103 * ----------------------------------------------------------------
106 InitScanRelation(SampleScanState *node, EState *estate, int eflags,
107 TableSampleClause *tablesample)
109 Relation currentRelation;
112 * get the relation object id from the relid'th entry in the range table,
113 * open that relation and acquire appropriate lock on it.
115 currentRelation = ExecOpenScanRelation(estate,
116 ((SampleScan *) node->ss.ps.plan)->scanrelid,
119 node->ss.ss_currentRelation = currentRelation;
122 * Even though we aren't going to do a conventional seqscan, it is useful
123 * to create a HeapScanDesc --- many of the fields in it are usable.
125 node->ss.ss_currentScanDesc =
126 heap_beginscan_sampling(currentRelation, estate->es_snapshot, 0, NULL,
127 tablesample->tsmseqscan,
128 tablesample->tsmpagemode);
130 /* and report the scan tuple slot's rowtype */
131 ExecAssignScanType(&node->ss, RelationGetDescr(currentRelation));
135 /* ----------------------------------------------------------------
137 * ----------------------------------------------------------------
140 ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
142 SampleScanState *scanstate;
143 RangeTblEntry *rte = rt_fetch(node->scanrelid,
144 estate->es_range_table);
146 Assert(outerPlan(node) == NULL);
147 Assert(innerPlan(node) == NULL);
148 Assert(rte->tablesample != NULL);
151 * create state structure
153 scanstate = makeNode(SampleScanState);
154 scanstate->ss.ps.plan = (Plan *) node;
155 scanstate->ss.ps.state = estate;
158 * Miscellaneous initialization
160 * create expression context for node
162 ExecAssignExprContext(estate, &scanstate->ss.ps);
165 * initialize child expressions
167 scanstate->ss.ps.targetlist = (List *)
168 ExecInitExpr((Expr *) node->plan.targetlist,
169 (PlanState *) scanstate);
170 scanstate->ss.ps.qual = (List *)
171 ExecInitExpr((Expr *) node->plan.qual,
172 (PlanState *) scanstate);
175 * tuple table initialization
177 ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
178 ExecInitScanTupleSlot(estate, &scanstate->ss);
181 * initialize scan relation
183 InitScanRelation(scanstate, estate, eflags, rte->tablesample);
185 scanstate->ss.ps.ps_TupFromTlist = false;
188 * Initialize result tuple type and projection info.
190 ExecAssignResultTypeFromTL(&scanstate->ss.ps);
191 ExecAssignScanProjectionInfo(&scanstate->ss);
193 scanstate->tsdesc = tablesample_init(scanstate, rte->tablesample);
198 /* ----------------------------------------------------------------
201 * frees any storage allocated through C routines.
202 * ----------------------------------------------------------------
205 ExecEndSampleScan(SampleScanState *node)
208 * Tell sampling function that we finished the scan.
210 tablesample_end(node->tsdesc);
213 * Free the exprcontext
215 ExecFreeExprContext(&node->ss.ps);
218 * clean out the tuple table
220 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
221 ExecClearTuple(node->ss.ss_ScanTupleSlot);
226 heap_endscan(node->ss.ss_currentScanDesc);
229 * close the heap relation.
231 ExecCloseScanRelation(node->ss.ss_currentRelation);
234 /* ----------------------------------------------------------------
236 * ----------------------------------------------------------------
239 /* ----------------------------------------------------------------
240 * ExecReScanSampleScan
242 * Rescans the relation.
244 * ----------------------------------------------------------------
247 ExecReScanSampleScan(SampleScanState *node)
249 heap_rescan(node->ss.ss_currentScanDesc, NULL);
252 * Tell sampling function to reset its state for rescan.
254 tablesample_reset(node->tsdesc);
256 ExecScanReScan(&node->ss);