1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
|
<!-- doc/src/sgml/custom-scan.sgml -->
<chapter id="custom-scan">
<title>Writing a Custom Scan Provider</title>
<indexterm zone="custom-scan">
<primary>custom scan provider</primary>
<secondary>handler for</secondary>
</indexterm>
<para>
<productname>PostgreSQL</productname> supports a set of experimental facilities which
are intended to allow extension modules to add new scan types to the system.
Unlike a <link linkend="fdwhandler">foreign data wrapper</link>, which is only
responsible for knowing how to scan its own foreign tables, a custom scan
provider can provide an alternative method of scanning any relation in the
system. Typically, the motivation for writing a custom scan provider will
be to allow the use of some optimization not supported by the core
system, such as caching or some form of hardware acceleration. This chapter
outlines how to write a new custom scan provider.
</para>
<para>
Implementing a new type of custom scan is a three-step process. First,
during planning, it is necessary to generate access paths representing a
scan using the proposed strategy. Second, if one of those access paths
is selected by the planner as the optimal strategy for scanning a
particular relation, the access path must be converted to a plan.
Finally, it must be possible to execute the plan and generate the same
results that would have been generated for any other access path targeting
the same relation.
</para>
<sect1 id="custom-scan-path">
<title>Creating Custom Scan Paths</title>
<para>
A custom scan provider will typically add paths for a base relation by
setting the following hook, which is called after the core code has
generated all the access paths it can for the relation (except for
Gather paths, which are made after this call so that they can use
partial paths added by the hook):
<programlisting>
typedef void (*set_rel_pathlist_hook_type) (PlannerInfo *root,
RelOptInfo *rel,
Index rti,
RangeTblEntry *rte);
extern PGDLLIMPORT set_rel_pathlist_hook_type set_rel_pathlist_hook;
</programlisting>
</para>
<para>
Although this hook function can be used to examine, modify, or remove
paths generated by the core system, a custom scan provider will typically
confine itself to generating <structname>CustomPath</structname> objects and adding
them to <literal>rel</literal> using <function>add_path</function>. The custom scan
provider is responsible for initializing the <structname>CustomPath</structname>
object, which is declared like this:
<programlisting>
typedef struct CustomPath
{
Path path;
uint32 flags;
List *custom_paths;
List *custom_private;
const CustomPathMethods *methods;
} CustomPath;
</programlisting>
</para>
<para>
<structfield>path</structfield> must be initialized as for any other path, including
the row-count estimate, start and total cost, and sort ordering provided
by this path. <structfield>flags</structfield> is a bit mask, which
specifies whether the scan provider can support certain optional
capabilities. <structfield>flags</structfield> should include
<literal>CUSTOMPATH_SUPPORT_BACKWARD_SCAN</literal> if the custom path can support
a backward scan, <literal>CUSTOMPATH_SUPPORT_MARK_RESTORE</literal> if it
can support mark and restore,
and <literal>CUSTOMPATH_SUPPORT_PROJECTION</literal> if it can perform
projections. (If <literal>CUSTOMPATH_SUPPORT_PROJECTION</literal> is not
set, the scan node will only be asked to produce Vars of the scanned
relation; while if that flag is set, the scan node must be able to
evaluate scalar expressions over these Vars.)
An optional <structfield>custom_paths</structfield> is a list of <structname>Path</structname>
nodes used by this custom-path node; these will be transformed into
<structname>Plan</structname> nodes by planner.
<structfield>custom_private</structfield> can be used to store the custom path's
private data. Private data should be stored in a form that can be handled
by <literal>nodeToString</literal>, so that debugging routines that attempt to
print the custom path will work as designed. <structfield>methods</structfield> must
point to a (usually statically allocated) object implementing the required
custom path methods, which are further detailed below.
</para>
<para>
A custom scan provider can also provide join paths. Just as for base
relations, such a path must produce the same output as would normally be
produced by the join it replaces. To do this, the join provider should
set the following hook, and then within the hook function,
create <structname>CustomPath</structname> path(s) for the join relation.
<programlisting>
typedef void (*set_join_pathlist_hook_type) (PlannerInfo *root,
RelOptInfo *joinrel,
RelOptInfo *outerrel,
RelOptInfo *innerrel,
JoinType jointype,
JoinPathExtraData *extra);
extern PGDLLIMPORT set_join_pathlist_hook_type set_join_pathlist_hook;
</programlisting>
This hook will be invoked repeatedly for the same join relation, with
different combinations of inner and outer relations; it is the
responsibility of the hook to minimize duplicated work.
</para>
<sect2 id="custom-scan-path-callbacks">
<title>Custom Scan Path Callbacks</title>
<para>
<programlisting>
Plan *(*PlanCustomPath) (PlannerInfo *root,
RelOptInfo *rel,
CustomPath *best_path,
List *tlist,
List *clauses,
List *custom_plans);
</programlisting>
Convert a custom path to a finished plan. The return value will generally
be a <literal>CustomScan</literal> object, which the callback must allocate and
initialize. See <xref linkend="custom-scan-plan"/> for more details.
</para>
<para>
<programlisting>
List *(*ReparameterizeCustomPathByChild) (PlannerInfo *root,
List *custom_private,
RelOptInfo *child_rel);
</programlisting>
This callback is called while converting a path parameterized by the
top-most parent of the given child relation <literal>child_rel</literal>
to be parameterized by the child relation. The callback is used to
reparameterize any paths or translate any expression nodes saved in the
given <literal>custom_private</literal> member of a
<structname>CustomPath</structname>. The callback may use
<literal>reparameterize_path_by_child</literal>,
<literal>adjust_appendrel_attrs</literal> or
<literal>adjust_appendrel_attrs_multilevel</literal> as required.
</para>
</sect2>
</sect1>
<sect1 id="custom-scan-plan">
<title>Creating Custom Scan Plans</title>
<para>
A custom scan is represented in a finished plan tree using the following
structure:
<programlisting>
typedef struct CustomScan
{
Scan scan;
uint32 flags;
List *custom_plans;
List *custom_exprs;
List *custom_private;
List *custom_scan_tlist;
Bitmapset *custom_relids;
const CustomScanMethods *methods;
} CustomScan;
</programlisting>
</para>
<para>
<structfield>scan</structfield> must be initialized as for any other scan, including
estimated costs, target lists, qualifications, and so on.
<structfield>flags</structfield> is a bit mask with the same meaning as in
<structname>CustomPath</structname>.
<structfield>custom_plans</structfield> can be used to store child
<structname>Plan</structname> nodes.
<structfield>custom_exprs</structfield> should be used to
store expression trees that will need to be fixed up by
<filename>setrefs.c</filename> and <filename>subselect.c</filename>, while
<structfield>custom_private</structfield> should be used to store other private data
that is only used by the custom scan provider itself.
<structfield>custom_scan_tlist</structfield> can be NIL when scanning a base
relation, indicating that the custom scan returns scan tuples that match
the base relation's row type. Otherwise it is a target list describing
the actual scan tuples. <structfield>custom_scan_tlist</structfield> must be
provided for joins, and could be provided for scans if the custom scan
provider can compute some non-Var expressions.
<structfield>custom_relids</structfield> is set by the core code to the set of
relations (range table indexes) that this scan node handles; except when
this scan is replacing a join, it will have only one member.
<structfield>methods</structfield> must point to a (usually statically allocated)
object implementing the required custom scan methods, which are further
detailed below.
</para>
<para>
When a <structname>CustomScan</structname> scans a single relation,
<structfield>scan.scanrelid</structfield> must be the range table index of the table
to be scanned. When it replaces a join, <structfield>scan.scanrelid</structfield>
should be zero.
</para>
<para>
Plan trees must be able to be duplicated using <function>copyObject</function>,
so all the data stored within the <quote>custom</quote> fields must consist of
nodes that that function can handle. Furthermore, custom scan providers
cannot substitute a larger structure that embeds
a <structname>CustomScan</structname> for the structure itself, as would be possible
for a <structname>CustomPath</structname> or <structname>CustomScanState</structname>.
</para>
<sect2 id="custom-scan-plan-callbacks">
<title>Custom Scan Plan Callbacks</title>
<para>
<programlisting>
Node *(*CreateCustomScanState) (CustomScan *cscan);
</programlisting>
Allocate a <structname>CustomScanState</structname> for this
<structname>CustomScan</structname>. The actual allocation will often be larger than
required for an ordinary <structname>CustomScanState</structname>, because many
providers will wish to embed that as the first field of a larger structure.
The value returned must have the node tag and <structfield>methods</structfield>
set appropriately, but other fields should be left as zeroes at this
stage; after <function>ExecInitCustomScan</function> performs basic initialization,
the <function>BeginCustomScan</function> callback will be invoked to give the
custom scan provider a chance to do whatever else is needed.
</para>
</sect2>
</sect1>
<sect1 id="custom-scan-execution">
<title>Executing Custom Scans</title>
<para>
When a <structfield>CustomScan</structfield> is executed, its execution state is
represented by a <structfield>CustomScanState</structfield>, which is declared as
follows:
<programlisting>
typedef struct CustomScanState
{
ScanState ss;
uint32 flags;
const CustomExecMethods *methods;
} CustomScanState;
</programlisting>
</para>
<para>
<structfield>ss</structfield> is initialized as for any other scan state,
except that if the scan is for a join rather than a base relation,
<literal>ss.ss_currentRelation</literal> is left NULL.
<structfield>flags</structfield> is a bit mask with the same meaning as in
<structname>CustomPath</structname> and <structname>CustomScan</structname>.
<structfield>methods</structfield> must point to a (usually statically allocated)
object implementing the required custom scan state methods, which are
further detailed below. Typically, a <structname>CustomScanState</structname>, which
need not support <function>copyObject</function>, will actually be a larger
structure embedding the above as its first member.
</para>
<sect2 id="custom-scan-execution-callbacks">
<title>Custom Scan Execution Callbacks</title>
<para>
<programlisting>
void (*BeginCustomScan) (CustomScanState *node,
EState *estate,
int eflags);
</programlisting>
Complete initialization of the supplied <structname>CustomScanState</structname>.
Standard fields have been initialized by <function>ExecInitCustomScan</function>,
but any private fields should be initialized here.
</para>
<para>
<programlisting>
TupleTableSlot *(*ExecCustomScan) (CustomScanState *node);
</programlisting>
Fetch the next scan tuple. If any tuples remain, it should fill
<literal>ps_ResultTupleSlot</literal> with the next tuple in the current scan
direction, and then return the tuple slot. If not,
<literal>NULL</literal> or an empty slot should be returned.
</para>
<para>
<programlisting>
void (*EndCustomScan) (CustomScanState *node);
</programlisting>
Clean up any private data associated with the <literal>CustomScanState</literal>.
This method is required, but it does not need to do anything if there is
no associated data or it will be cleaned up automatically.
</para>
<para>
<programlisting>
void (*ReScanCustomScan) (CustomScanState *node);
</programlisting>
Rewind the current scan to the beginning and prepare to rescan the
relation.
</para>
<para>
<programlisting>
void (*MarkPosCustomScan) (CustomScanState *node);
</programlisting>
Save the current scan position so that it can subsequently be restored
by the <function>RestrPosCustomScan</function> callback. This callback is
optional, and need only be supplied if the
<literal>CUSTOMPATH_SUPPORT_MARK_RESTORE</literal> flag is set.
</para>
<para>
<programlisting>
void (*RestrPosCustomScan) (CustomScanState *node);
</programlisting>
Restore the previous scan position as saved by the
<function>MarkPosCustomScan</function> callback. This callback is optional,
and need only be supplied if the
<literal>CUSTOMPATH_SUPPORT_MARK_RESTORE</literal> flag is set.
</para>
<para>
<programlisting>
Size (*EstimateDSMCustomScan) (CustomScanState *node,
ParallelContext *pcxt);
</programlisting>
Estimate the amount of dynamic shared memory that will be required
for parallel operation. This may be higher than the amount that will
actually be used, but it must not be lower. The return value is in bytes.
This callback is optional, and need only be supplied if this custom
scan provider supports parallel execution.
</para>
<para>
<programlisting>
void (*InitializeDSMCustomScan) (CustomScanState *node,
ParallelContext *pcxt,
void *coordinate);
</programlisting>
Initialize the dynamic shared memory that will be required for parallel
operation. <literal>coordinate</literal> points to a shared memory area of
size equal to the return value of <function>EstimateDSMCustomScan</function>.
This callback is optional, and need only be supplied if this custom
scan provider supports parallel execution.
</para>
<para>
<programlisting>
void (*ReInitializeDSMCustomScan) (CustomScanState *node,
ParallelContext *pcxt,
void *coordinate);
</programlisting>
Re-initialize the dynamic shared memory required for parallel operation
when the custom-scan plan node is about to be re-scanned.
This callback is optional, and need only be supplied if this custom
scan provider supports parallel execution.
Recommended practice is that this callback reset only shared state,
while the <function>ReScanCustomScan</function> callback resets only local
state. Currently, this callback will be called
before <function>ReScanCustomScan</function>, but it's best not to rely on
that ordering.
</para>
<para>
<programlisting>
void (*InitializeWorkerCustomScan) (CustomScanState *node,
shm_toc *toc,
void *coordinate);
</programlisting>
Initialize a parallel worker's local state based on the shared state
set up by the leader during <function>InitializeDSMCustomScan</function>.
This callback is optional, and need only be supplied if this custom
scan provider supports parallel execution.
</para>
<para>
<programlisting>
void (*ShutdownCustomScan) (CustomScanState *node);
</programlisting>
Release resources when it is anticipated the node will not be executed
to completion. This is not called in all cases; sometimes,
<literal>EndCustomScan</literal> may be called without this function having
been called first. Since the DSM segment used by parallel query is
destroyed just after this callback is invoked, custom scan providers that
wish to take some action before the DSM segment goes away should implement
this method.
</para>
<para>
<programlisting>
void (*ExplainCustomScan) (CustomScanState *node,
List *ancestors,
ExplainState *es);
</programlisting>
Output additional information for <command>EXPLAIN</command> of a custom-scan
plan node. This callback is optional. Common data stored in the
<structname>ScanState</structname>, such as the target list and scan relation, will
be shown even without this callback, but the callback allows the display
of additional, private state.
</para>
</sect2>
</sect1>
</chapter>
|