学习PostgreSQL的FDW(#2)-源码跟踪

上篇大概介绍了FDW必须实现的7个回调函数学习PostgreSQL的FDW(#1),本篇将从源码跟踪,这7个回调函数的调用时机,以PostgreSQL11beta2的postgres_fdw为例,分析PostgreSQL在查询外部表时,究竟做了什么。

测试前准备

IP为192.168.117.56的虚拟机安装了PostgreSQL10;
IP为192.168.118.56的虚拟机安装了PostgreSQL11beta2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
testdb=# -- 在117.56中创建测试表
testdb=# create table t_fdw(id int,c1 char(10),c2 varchar(10));
CREATE TABLE
testdb=# insert into t_fdw values (1,'1','2');
INSERT 0 1
testdb=# insert into t_fdw values (2,'1','2');
INSERT 0 1
testdb=# insert into t_fdw values (3,'1','2');
INSERT 0 1
testdb=# insert into t_fdw values (4,'1','2');
INSERT 0 1
testdb=# insert into t_fdw values (5,'1','2');
INSERT 0 1
testdb=# insert into t_fdw values (6,'1','2');
INSERT 0 1
testdb=# insert into t_fdw values (7,'1','2');
INSERT 0 1
testdb=# insert into t_fdw values (8,'1','2');
INSERT 0 1
testdb=# insert into t_fdw values (9,'1','2');
INSERT 0 1
testdb=# insert into t_fdw values (10,'1','2');
INSERT 0 1

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
fdw=# -- 在118.56中创建postgres_fdw扩展
fdw=# create extension postgres_fdw ;
CREATE EXTENSION
fdw=# \dx;
List of installed extensions
Name | Version | Schema | Description
--------------+---------+------------+----------------------------------------------------
plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
postgres_fdw | 1.0 | public | foreign-data wrapper for remote PostgreSQL servers
(2 rows)
fdw=# -- 创建外部服务器
fdw=# create server pg_117_56 foreign data wrapper postgres_fdw options (host '192.168.117.56',port '5432',dbname 'testdb');
CREATE SERVER
fdw=# \des
List of foreign servers
Name | Owner | Foreign-data wrapper
-----------+-------+----------------------
pg_117_56 | xdb | postgres_fdw
(1 row)

fdw=# --创建用户映射
fdw=# create user MAPPING FOR PUBLIC server pg_117_56 options (user 'xdb',password 'test');
CREATE USER MAPPING
fdw=# \deu+
List of user mappings
Server | User name | FDW options
-----------+-----------+---------------------------------
pg_117_56 | public | ("user" 'xdb', password 'test')
(1 row)
fdw=# -- 创建外部表
create foreign table t_fdw(id int, c1 char(10),c2 varchar(10)) server pg_117_56 options(schema_name 'public',table_name 't_fdw');
CREATE FOREIGN TABLE
fdw=# \d
List of relations
Schema | Name | Type | Owner
--------+-------+---------------+-------
public | t_fdw | foreign table | xdb
(1 row)

跟踪分析

1
2
3
4
5
fdw=# select pg_backend_pid();
pg_backend_pid
----------------
2382
(1 row)

使用gdb跟踪查询过程:

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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
[root@localhost ~]# gdb -p 2382
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-110.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Attaching to process 2382
...
(gdb)
# 设置断点
(gdb) b postgresGetForeignRelSize
Function "postgresGetForeignRelSize" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (postgresGetForeignRelSize) pending.
(gdb) b postgresGetForeignPaths
Function "postgresGetForeignPaths" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 2 (postgresGetForeignPaths) pending.
(gdb) b postgresGetForeignPlan
Function "postgresGetForeignPlan" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 3 (postgresGetForeignPlan) pending.
(gdb) b postgresBeginForeignScan
Function "postgresBeginForeignScan" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 4 (postgresBeginForeignScan) pending.
(gdb) b postgresIterateForeignScan
Function "postgresIterateForeignScan" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 5 (postgresIterateForeignScan) pending.
(gdb) b postgresReScanForeignScan
Function "postgresReScanForeignScan" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 6 (postgresReScanForeignScan) pending.
(gdb) b postgresEndForeignScan
Function "postgresEndForeignScan" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 7 (postgresEndForeignScan) pending.

# 切换到psql,执行查询语句
fdw=# select * from t_fdw;
# (挂起状态)

# 切换回gdb
(gdb) c
Continuing.

Breakpoint 1, postgresGetForeignRelSize (root=0x13342e8, baserel=0x13349e8, foreigntableid=16392) at postgres_fdw.c:522
522 {
(gdb) bt
#0 postgresGetForeignRelSize (root=0x13342e8, baserel=0x13349e8, foreigntableid=16392) at postgres_fdw.c:522
#1 0x000000000065fde5 in set_foreign_size (rte=0x130f778, rel=0x13349e8, root=0x13342e8) at allpaths.c:839
#2 set_rel_size (root=root@entry=0x13342e8, rel=rel@entry=0x13349e8, rti=rti@entry=1, rte=0x130f778) at allpaths.c:351
#3 0x000000000066097d in set_base_rel_sizes (root=<optimized out>) at allpaths.c:281
#4 make_one_rel (root=root@entry=0x13342e8, joinlist=joinlist@entry=0x1334e50) at allpaths.c:179
#5 0x000000000067de9e in query_planner (root=root@entry=0x13342e8, tlist=tlist@entry=0x1334788, qp_callback=qp_callback@entry=0x67f290 <standard_qp_callback>, qp_extra=qp_extra@entry=0x7fff8c772f00) at planmain.c:259
#6 0x0000000000681f43 in grouping_planner (root=root@entry=0x13342e8, inheritance_update=inheritance_update@entry=false, tuple_fraction=<optimized out>, tuple_fraction@entry=0) at planner.c:1897
#7 0x0000000000684218 in subquery_planner (glob=glob@entry=0x130fc38, parse=parse@entry=0x130f668, parent_root=parent_root@entry=0x0, hasRecursion=hasRecursion@entry=false, tuple_fraction=tuple_fraction@entry=0) at planner.c:966
#8 0x0000000000685236 in standard_planner (parse=0x130f668, cursorOptions=256, boundParams=0x0) at planner.c:405
#9 0x000000000072178c in pg_plan_query (querytree=querytree@entry=0x130f668, cursorOptions=cursorOptions@entry=256, boundParams=boundParams@entry=0x0) at postgres.c:809
#10 0x000000000072186e in pg_plan_queries (querytrees=<optimized out>, cursorOptions=cursorOptions@entry=256, boundParams=boundParams@entry=0x0) at postgres.c:875
#11 0x0000000000721cda in exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1050
#12 0x0000000000722e62 in PostgresMain (argc=<optimized out>, argv=argv@entry=0x1338568, dbname=0x1338450 "fdw", username=<optimized out>) at postgres.c:4153
#13 0x000000000047a861 in BackendRun (port=0x1330430) at postmaster.c:4361
#14 BackendStartup (port=0x1330430) at postmaster.c:4033
#15 ServerLoop () at postmaster.c:1706
#16 0x00000000006babb9 in PostmasterMain (argc=argc@entry=3, argv=argv@entry=0x13093c0) at postmaster.c:1379
#17 0x000000000047b2a1 in main (argc=3, argv=0x13093c0) at main.c:228

(gdb) finish
Run till exit from #0 postgresGetForeignRelSize (root=0x13342e8, baserel=0x13349e8, foreigntableid=16392) at postgres_fdw.c:535
set_foreign_size (rte=0x130f778, rel=0x13349e8, root=0x13342e8) at allpaths.c:842
842 rel->rows = clamp_row_est(rel->rows);
(gdb) finish
Run till exit from #0 set_foreign_size (rte=0x130f778, rel=0x13349e8, root=0x13342e8) at allpaths.c:842
415 }
(gdb) finish
Run till exit from #0 set_rel_size (root=root@entry=0x13342e8, rel=rel@entry=0x13349e8, rti=rti@entry=1, rte=<optimized out>)
at allpaths.c:415
set_base_rel_sizes (root=<optimized out>) at allpaths.c:253
253 for (rti = 1; rti < root->simple_rel_array_size; rti++)
(gdb) finish
Run till exit from #0 set_base_rel_sizes (root=<optimized out>) at allpaths.c:253
180 set_base_rel_pathlists(root);
(gdb) finish
Run till exit from #0 make_one_rel (root=root@entry=0x13342e8, joinlist=joinlist@entry=0x1334e50) at allpaths.c:180

Breakpoint 2, postgresGetForeignPaths (root=0x13342e8, baserel=0x13349e8, foreigntableid=16392) at postgres_fdw.c:921
921 {
(gdb) bt
#0 postgresGetForeignPaths (root=0x13342e8, baserel=0x13349e8, foreigntableid=16392) at postgres_fdw.c:921
#1 0x0000000000660452 in set_foreign_pathlist (rte=0x130f778, rel=0x13349e8, root=0x13342e8) at allpaths.c:853
#2 set_rel_pathlist (root=root@entry=0x13342e8, rel=0x13349e8, rti=rti@entry=1, rte=0x130f778) at allpaths.c:442
#3 0x0000000000660a30 in set_base_rel_pathlists (root=<optimized out>) at allpaths.c:310
#4 make_one_rel (root=root@entry=0x13342e8, joinlist=joinlist@entry=0x1334e50) at allpaths.c:180
#5 0x000000000067de9e in query_planner (root=root@entry=0x13342e8, tlist=tlist@entry=0x1334788, qp_callback=qp_callback@entry=0x67f290 <standard_qp_callback>, qp_extra=qp_extra@entry=0x7fff8c772f00) at planmain.c:259
#6 0x0000000000681f43 in grouping_planner (root=root@entry=0x13342e8, inheritance_update=inheritance_update@entry=false, tuple_fraction=<optimized out>, tuple_fraction@entry=0) at planner.c:1897
#7 0x0000000000684218 in subquery_planner (glob=glob@entry=0x130fc38, parse=parse@entry=0x130f668, parent_root=parent_root@entry=0x0, hasRecursion=hasRecursion@entry=false, tuple_fraction=tuple_fraction@entry=0) at planner.c:966
#8 0x0000000000685236 in standard_planner (parse=0x130f668, cursorOptions=256, boundParams=0x0) at planner.c:405
#9 0x000000000072178c in pg_plan_query (querytree=querytree@entry=0x130f668, cursorOptions=cursorOptions@entry=256, boundParams=boundParams@entry=0x0) at postgres.c:809
#10 0x000000000072186e in pg_plan_queries (querytrees=<optimized out>, cursorOptions=cursorOptions@entry=256, boundParams=boundParams@entry=0x0) at postgres.c:875
#11 0x0000000000721cda in exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1050
#12 0x0000000000722e62 in PostgresMain (argc=<optimized out>, argv=argv@entry=0x1338568, dbname=0x1338450 "fdw", username=<optimized out>) at postgres.c:4153
#13 0x000000000047a861 in BackendRun (port=0x1330430) at postmaster.c:4361
#14 BackendStartup (port=0x1330430) at postmaster.c:4033
#15 ServerLoop () at postmaster.c:1706
#16 0x00000000006babb9 in PostmasterMain (argc=argc@entry=3, argv=argv@entry=0x13093c0) at postmaster.c:1379
#17 0x000000000047b2a1 in main (argc=3, argv=0x13093c0) at main.c:228
(gdb) finish
Run till exit from #0 postgresGetForeignPaths (root=0x13342e8, baserel=0x13349e8, foreigntableid=16392) at postgres_fdw.c:921
0x0000000000660452 in set_foreign_pathlist (rte=0x130f778, rel=0x13349e8, root=0x13342e8) at allpaths.c:853
853 rel->fdwroutine->GetForeignPaths(root, rel, rte->relid);
(gdb) finish
Run till exit from #0 0x0000000000660452 in set_foreign_pathlist (rte=0x130f778, rel=0x13349e8, root=0x13342e8)
at allpaths.c:853
495 if (rel->reloptkind == RELOPT_BASEREL &&
(gdb) finish
Run till exit from #0 set_rel_pathlist (root=root@entry=0x13342e8, rel=0x13349e8, rti=rti@entry=1, rte=0x130f778)
at allpaths.c:495
0x0000000000660a30 in set_base_rel_pathlists (root=<optimized out>) at allpaths.c:310
310 set_rel_pathlist(root, rel, rti, root->simple_rte_array[rti]);
(gdb) finish
Run till exit from #0 0x0000000000660a30 in set_base_rel_pathlists (root=<optimized out>) at allpaths.c:310
185 rel = make_rel_from_joinlist(root, joinlist);
(gdb) finish
Run till exit from #0 make_one_rel (root=root@entry=0x13342e8, joinlist=joinlist@entry=0x1334e50) at allpaths.c:185
query_planner (root=root@entry=0x13342e8, tlist=tlist@entry=0x1334788,
qp_callback=qp_callback@entry=0x67f290 <standard_qp_callback>, qp_extra=qp_extra@entry=0x7fff8c772f00) at planmain.c:262
262 if (!final_rel || !final_rel->cheapest_total_path ||
Value returned is $3 = (RelOptInfo *) 0x13349e8
(gdb) finish
Run till exit from #0 query_planner (root=root@entry=0x13342e8, tlist=tlist@entry=0x1334788,
qp_callback=qp_callback@entry=0x67f290 <standard_qp_callback>, qp_extra=qp_extra@entry=0x7fff8c772f00) at planmain.c:262
grouping_planner (root=root@entry=0x13342e8, inheritance_update=inheritance_update@entry=false, tuple_fraction=<optimized out>,
tuple_fraction@entry=0) at planner.c:1907
1907 final_target = create_pathtarget(root, tlist);
Value returned is $4 = (RelOptInfo *) 0x13349e8
(gdb) finish
Run till exit from #0 grouping_planner (root=root@entry=0x13342e8, inheritance_update=inheritance_update@entry=false,
tuple_fraction=<optimized out>, tuple_fraction@entry=0) at planner.c:1907
subquery_planner (glob=glob@entry=0x130fc38, parse=parse@entry=0x130f668, parent_root=parent_root@entry=0x0,
hasRecursion=hasRecursion@entry=false, tuple_fraction=tuple_fraction@entry=0) at planner.c:972
972 SS_identify_outer_params(root);
(gdb) finish
Run till exit from #0 subquery_planner (glob=glob@entry=0x130fc38, parse=parse@entry=0x130f668,
parent_root=parent_root@entry=0x0, hasRecursion=hasRecursion@entry=false, tuple_fraction=tuple_fraction@entry=0)
at planner.c:972
standard_planner (parse=0x130f668, cursorOptions=256, boundParams=0x0) at planner.c:409
409 final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
Value returned is $5 = (PlannerInfo *) 0x13342e8
(gdb) finish
Run till exit from #0 standard_planner (parse=0x130f668, cursorOptions=256, boundParams=0x0) at planner.c:409

Breakpoint 3, postgresGetForeignPlan (root=0x13342e8, foreignrel=0x13349e8, foreigntableid=16392, best_path=0x1334dc0,
tlist=0x13cbdd8, scan_clauses=0x0, outer_plan=0x0) at postgres_fdw.c:1131
1131 {
(gdb) bt
#0 postgresGetForeignPlan (root=0x13342e8, foreignrel=0x13349e8, foreigntableid=16392, best_path=0x1334dc0, tlist=0x13cbdd8, scan_clauses=0x0, outer_plan=0x0) at postgres_fdw.c:1131
#1 0x000000000067a0c1 in create_foreignscan_plan (scan_clauses=<optimized out>, tlist=0x13cbdd8, best_path=0x1334dc0, root=0x13342e8) at createplan.c:3597
#2 create_scan_plan (root=root@entry=0x13342e8, best_path=best_path@entry=0x1334dc0, flags=<optimized out>, flags@entry=1) at createplan.c:714
#3 0x0000000000677557 in create_plan_recurse (root=root@entry=0x13342e8, best_path=0x1334dc0, flags=flags@entry=1) at createplan.c:390
#4 0x0000000000679dc9 in create_plan (root=root@entry=0x13342e8, best_path=<optimized out>) at createplan.c:327
#5 0x0000000000685264 in standard_planner (parse=0x130f668, cursorOptions=256, boundParams=0x0) at planner.c:412
#6 0x000000000072178c in pg_plan_query (querytree=querytree@entry=0x130f668, cursorOptions=cursorOptions@entry=256, boundParams=boundParams@entry=0x0) at postgres.c:809
#7 0x000000000072186e in pg_plan_queries (querytrees=<optimized out>, cursorOptions=cursorOptions@entry=256, boundParams=boundParams@entry=0x0) at postgres.c:875
#8 0x0000000000721cda in exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1050
#9 0x0000000000722e62 in PostgresMain (argc=<optimized out>, argv=argv@entry=0x1338568, dbname=0x1338450 "fdw", username=<optimized out>) at postgres.c:4153
#10 0x000000000047a861 in BackendRun (port=0x1330430) at postmaster.c:4361
#11 BackendStartup (port=0x1330430) at postmaster.c:4033
#12 ServerLoop () at postmaster.c:1706
#13 0x00000000006babb9 in PostmasterMain (argc=argc@entry=3, argv=argv@entry=0x13093c0) at postmaster.c:1379
#14 0x000000000047b2a1 in main (argc=3, argv=0x13093c0) at main.c:228
(gdb) finish
Run till exit from #0 postgresGetForeignPlan (root=0x13342e8, foreignrel=0x13349e8, foreigntableid=16392, best_path=0x1334dc0,
tlist=0x13cbdd8, scan_clauses=0x0, outer_plan=0x0) at postgres_fdw.c:1131
create_foreignscan_plan (scan_clauses=<optimized out>, tlist=0x13cbdd8, best_path=0x1334dc0, root=0x13342e8) at createplan.c:3603
3603 copy_generic_path_info(&scan_plan->scan.plan, &best_path->path);
Value returned is $6 = (ForeignScan *) 0x13105b0
(gdb) finish
Run till exit from #0 create_foreignscan_plan (scan_clauses=<optimized out>, tlist=0x13cbdd8, best_path=0x1334dc0,
root=0x13342e8) at createplan.c:3603
718 break;
(gdb) finish
Run till exit from #0 create_scan_plan (root=root@entry=0x13342e8, best_path=best_path@entry=0x1334dc0, flags=<optimized out>,
flags@entry=1) at createplan.c:718
0x0000000000677557 in create_plan_recurse (root=root@entry=0x13342e8, best_path=0x1334dc0, flags=flags@entry=1)
at createplan.c:390
390 plan = create_scan_plan(root, best_path, flags);
Value returned is $7 = (Plan *) 0x13105b0
(gdb) finish
Run till exit from #0 0x0000000000677557 in create_plan_recurse (root=root@entry=0x13342e8, best_path=0x1334dc0,
flags=flags@entry=1) at createplan.c:390
create_plan (root=root@entry=0x13342e8, best_path=<optimized out>) at createplan.c:336
336 if (!IsA(plan, ModifyTable))
Value returned is $8 = (Plan *) 0x13105b0
(gdb) finish
Run till exit from #0 create_plan (root=root@entry=0x13342e8, best_path=<optimized out>) at createplan.c:336
standard_planner (parse=0x130f668, cursorOptions=256, boundParams=0x0) at planner.c:418
418 if (cursorOptions & CURSOR_OPT_SCROLL)
Value returned is $9 = (Plan *) 0x13105b0
(gdb) finish
Run till exit from #0 standard_planner (parse=0x130f668, cursorOptions=256, boundParams=0x0) at planner.c:418
pg_plan_query (querytree=querytree@entry=0x130f668, cursorOptions=cursorOptions@entry=256, boundParams=boundParams@entry=0x0)
at postgres.c:811
811 if (log_planner_stats)
Value returned is $10 = (PlannedStmt *) 0x130f8d8
(gdb) finish
Run till exit from #0 pg_plan_query (querytree=querytree@entry=0x130f668, cursorOptions=cursorOptions@entry=256,
boundParams=boundParams@entry=0x0) at postgres.c:811
0x000000000072186e in pg_plan_queries (querytrees=<optimized out>, cursorOptions=cursorOptions@entry=256,
boundParams=boundParams@entry=0x0) at postgres.c:875
875 stmt = pg_plan_query(query, cursorOptions, boundParams);
Value returned is $11 = (PlannedStmt *) 0x130f8d8
(gdb) finish
Run till exit from #0 0x000000000072186e in pg_plan_queries (querytrees=<optimized out>, cursorOptions=cursorOptions@entry=256,
boundParams=boundParams@entry=0x0) at postgres.c:875
0x0000000000721cda in exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1050
1050 plantree_list = pg_plan_queries(querytree_list,
Value returned is $12 = (List *) 0x13cc7d8
(gdb) finish
Run till exit from #0 0x0000000000721cda in exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1050

Breakpoint 4, postgresBeginForeignScan (node=0x13bf120, eflags=16) at postgres_fdw.c:1314
1314 {
(gdb) bt
#0 postgresBeginForeignScan (node=0x13bf120, eflags=16) at postgres_fdw.c:1314
#1 0x00000000006190fc in ExecInitForeignScan (node=node@entry=0x13105b0, estate=estate@entry=0x13bef10, eflags=eflags@entry=16) at nodeForeignscan.c:229
#2 0x00000000005f6694 in ExecInitNode (node=node@entry=0x13105b0, estate=estate@entry=0x13bef10, eflags=eflags@entry=16) at execProcnode.c:277
#3 0x00000000005f11c5 in InitPlan (eflags=16, queryDesc=<optimized out>) at execMain.c:1049
#4 standard_ExecutorStart (queryDesc=<optimized out>, eflags=16) at execMain.c:264
#5 0x00000000007255e2 in PortalStart (portal=portal@entry=0x1373f50, params=params@entry=0x0, eflags=eflags@entry=0, snapshot=snapshot@entry=0x0) at pquery.c:520
#6 0x0000000000721b42 in exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1083
#7 0x0000000000722e62 in PostgresMain (argc=<optimized out>, argv=argv@entry=0x1338568, dbname=0x1338450 "fdw", username=<optimized out>) at postgres.c:4153
#8 0x000000000047a861 in BackendRun (port=0x1330430) at postmaster.c:4361
#9 BackendStartup (port=0x1330430) at postmaster.c:4033
#10 ServerLoop () at postmaster.c:1706
#11 0x00000000006babb9 in PostmasterMain (argc=argc@entry=3, argv=argv@entry=0x13093c0) at postmaster.c:1379
#12 0x000000000047b2a1 in main (argc=3, argv=0x13093c0) at main.c:228
(gdb) finish
Run till exit from #0 postgresBeginForeignScan (node=0x13bf120, eflags=16) at postgres_fdw.c:1314
0x00000000006190fc in ExecInitForeignScan (node=node@entry=0x13105b0, estate=estate@entry=0x13bef10, eflags=eflags@entry=16)
at nodeForeignscan.c:229
229 fdwroutine->BeginForeignScan(scanstate, eflags);
(gdb) finish
Run till exit from #0 0x00000000006190fc in ExecInitForeignScan (node=node@entry=0x13105b0, estate=estate@entry=0x13bef10,
eflags=eflags@entry=16) at nodeForeignscan.c:229
0x00000000005f6694 in ExecInitNode (node=node@entry=0x13105b0, estate=estate@entry=0x13bef10, eflags=eflags@entry=16)
at execProcnode.c:277
277 result = (PlanState *) ExecInitForeignScan((ForeignScan *) node,
Value returned is $13 = (ForeignScanState *) 0x13bf120
(gdb) finish
Run till exit from #0 0x00000000005f6694 in ExecInitNode (node=node@entry=0x13105b0, estate=estate@entry=0x13bef10,
eflags=eflags@entry=16) at execProcnode.c:277
InitPlan (eflags=16, queryDesc=<optimized out>) at execMain.c:1054
1054 tupType = ExecGetResultType(planstate);
Value returned is $14 = (PlanState *) 0x13bf120
(gdb) finish
Run till exit from #0 InitPlan (eflags=16, queryDesc=<optimized out>) at execMain.c:1054
266 MemoryContextSwitchTo(oldcontext);
(gdb) finish
Run till exit from #0 standard_ExecutorStart (queryDesc=<optimized out>, eflags=16) at execMain.c:266
PortalStart (portal=portal@entry=0x1373f50, params=params@entry=0x0, eflags=eflags@entry=0, snapshot=snapshot@entry=0x0)
at pquery.c:525
525 portal->queryDesc = queryDesc;
(gdb) finish
Run till exit from #0 PortalStart (portal=portal@entry=0x1373f50, params=params@entry=0x0, eflags=eflags@entry=0,
snapshot=snapshot@entry=0x0) at pquery.c:525
exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1092
1092 if (IsA(parsetree->stmt, FetchStmt))
(gdb) finish
Run till exit from #0 exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1092

Breakpoint 5, postgresIterateForeignScan (node=0x13bf120) at postgres_fdw.c:1418
1418 {
(gdb) bt
#0 postgresIterateForeignScan (node=0x13bf120) at postgres_fdw.c:1418
#1 0x0000000000618f6b in ForeignNext (node=node@entry=0x13bf120) at nodeForeignscan.c:54
#2 0x00000000005f7b2a in ExecScanFetch (recheckMtd=0x618e40 <ForeignRecheck>, accessMtd=0x618ed0 <ForeignNext>, node=0x13bf120) at execScan.c:95
#3 ExecScan (node=0x13bf120, accessMtd=0x618ed0 <ForeignNext>, recheckMtd=0x618e40 <ForeignRecheck>) at execScan.c:145
#4 0x00000000005f000a in ExecProcNode (node=0x13bf120) at ../../../src/include/executor/executor.h:237
#5 ExecutePlan (execute_once=<optimized out>, dest=0x1335d78, direction=<optimized out>, numberTuples=0, sendTuples=true, operation=CMD_SELECT, use_parallel_mode=<optimized out>, planstate=0x13bf120, estate=0x13bef10) at execMain.c:1726
#6 standard_ExecutorRun (queryDesc=0x1330130, direction=<optimized out>, count=0, execute_once=<optimized out>) at execMain.c:363
#7 0x00000000007247fb in PortalRunSelect (portal=portal@entry=0x1373f50, forward=forward@entry=true, count=0, count@entry=9223372036854775807, dest=dest@entry=0x1335d78) at pquery.c:932
#8 0x0000000000725b10 in PortalRun (portal=portal@entry=0x1373f50, count=count@entry=9223372036854775807, isTopLevel=isTopLevel@entry=true, run_once=run_once@entry=true, dest=dest@entry=0x1335d78, altdest=altdest@entry=0x1335d78, completionTag=completionTag@entry=0x7fff8c773240 "") at pquery.c:773
#9 0x0000000000721bb7 in exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1122
#10 0x0000000000722e62 in PostgresMain (argc=<optimized out>, argv=argv@entry=0x1338568, dbname=0x1338450 "fdw", username=<optimized out>) at postgres.c:4153
#11 0x000000000047a861 in BackendRun (port=0x1330430) at postmaster.c:4361
#12 BackendStartup (port=0x1330430) at postmaster.c:4033
#13 ServerLoop () at postmaster.c:1706
#14 0x00000000006babb9 in PostmasterMain (argc=argc@entry=3, argv=argv@entry=0x13093c0) at postmaster.c:1379
#15 0x000000000047b2a1 in main (argc=3, argv=0x13093c0) at main.c:228
(gdb) finish
Run till exit from #0 postgresIterateForeignScan (node=0x13bf120) at postgres_fdw.c:1418
0x0000000000618f6b in ForeignNext (node=node@entry=0x13bf120) at nodeForeignscan.c:54
54 slot = node->fdwroutine->IterateForeignScan(node);
Value returned is $15 = (TupleTableSlot *) 0x13bf730
(gdb) finish
Run till exit from #0 0x0000000000618f6b in ForeignNext (node=node@entry=0x13bf120) at nodeForeignscan.c:54
0x00000000005f7b2a in ExecScanFetch (recheckMtd=0x618e40 <ForeignRecheck>, accessMtd=0x618ed0 <ForeignNext>, node=0x13bf120)
at execScan.c:95
95 return (*accessMtd) (node);
Value returned is $16 = (TupleTableSlot *) 0x13bf730
(gdb) finish
Run till exit from #0 0x00000000005f7b2a in ExecScanFetch (recheckMtd=0x618e40 <ForeignRecheck>,
accessMtd=0x618ed0 <ForeignNext>, node=0x13bf120) at execScan.c:95
219 }
(gdb) finish
Run till exit from #0 ExecScan (node=<optimized out>, accessMtd=0x618ed0 <ForeignNext>, recheckMtd=0x618e40 <ForeignRecheck>)
at execScan.c:219
ExecutePlan (execute_once=<optimized out>, dest=0x1335d78, direction=<optimized out>, numberTuples=0, sendTuples=true,
operation=CMD_SELECT, use_parallel_mode=<optimized out>, planstate=0x13bf120, estate=0x13bef10) at execMain.c:1732
1732 if (TupIsNull(slot))
Value returned is $17 = (TupleTableSlot *) 0x13bf730
(gdb) finish
Run till exit from #0 ExecutePlan (execute_once=<optimized out>, dest=0x1335d78, direction=<optimized out>, numberTuples=0,
sendTuples=true, operation=CMD_SELECT, use_parallel_mode=<optimized out>, planstate=0x13bf120, estate=0x13bef10)
at execMain.c:1732
363 ExecutePlan(estate,
(gdb) finish
Run till exit from #0 standard_ExecutorRun (queryDesc=0x1330130, direction=<optimized out>, count=0,
execute_once=<optimized out>) at execMain.c:363

Breakpoint 5, postgresIterateForeignScan (node=0x13bf120) at postgres_fdw.c:1418
1418 {
# 再次进入postgresIterateForeignScan.后续跳过中间的8次,
...

Breakpoint 5, postgresIterateForeignScan (node=0x13bf120) at postgres_fdw.c:1418
1418 {
(gdb) finish
Run till exit from #0 postgresIterateForeignScan (node=0x13bf120) at postgres_fdw.c:1418
0x0000000000618f6b in ForeignNext (node=node@entry=0x13bf120) at nodeForeignscan.c:54
54 slot = node->fdwroutine->IterateForeignScan(node);
Value returned is $45 = (TupleTableSlot *) 0x13bf730
(gdb) finish
Run till exit from #0 0x0000000000618f6b in ForeignNext (node=node@entry=0x13bf120) at nodeForeignscan.c:54
0x00000000005f7b2a in ExecScanFetch (recheckMtd=0x618e40 <ForeignRecheck>, accessMtd=0x618ed0 <ForeignNext>, node=0x13bf120)
at execScan.c:95
95 return (*accessMtd) (node);
Value returned is $46 = (TupleTableSlot *) 0x13bf730
(gdb) finish
Run till exit from #0 0x00000000005f7b2a in ExecScanFetch (recheckMtd=0x618e40 <ForeignRecheck>,
accessMtd=0x618ed0 <ForeignNext>, node=0x13bf120) at execScan.c:95
219 }
(gdb) finish
Run till exit from #0 ExecScan (node=<optimized out>, accessMtd=0x618ed0 <ForeignNext>, recheckMtd=0x618e40 <ForeignRecheck>)
at execScan.c:219
ExecutePlan (execute_once=<optimized out>, dest=0x1335d78, direction=<optimized out>, numberTuples=0, sendTuples=true,
operation=CMD_SELECT, use_parallel_mode=<optimized out>, planstate=0x13bf120, estate=0x13bef10) at execMain.c:1732
1732 if (TupIsNull(slot))
Value returned is $47 = (TupleTableSlot *) 0x13bf730
(gdb) finish
Run till exit from #0 ExecutePlan (execute_once=<optimized out>, dest=0x1335d78, direction=<optimized out>, numberTuples=0,
sendTuples=true, operation=CMD_SELECT, use_parallel_mode=<optimized out>, planstate=0x13bf120, estate=0x13bef10)
at execMain.c:1732
377 if (sendTuples)
(gdb) finish
Run till exit from #0 standard_ExecutorRun (queryDesc=0x1330130, direction=<optimized out>, count=0,
execute_once=<optimized out>) at execMain.c:377
PortalRunSelect (portal=portal@entry=0x1373f50, forward=forward@entry=true, count=0, count@entry=9223372036854775807,
dest=dest@entry=0x1335d78) at pquery.c:934
934 nprocessed = queryDesc->estate->es_processed;
(gdb) finish
Run till exit from #0 PortalRunSelect (portal=portal@entry=0x1373f50, forward=forward@entry=true, count=0,
count@entry=9223372036854775807, dest=dest@entry=0x1335d78) at pquery.c:934
PortalRun (portal=portal@entry=0x1373f50, count=count@entry=9223372036854775807, isTopLevel=isTopLevel@entry=true,
run_once=run_once@entry=true, dest=dest@entry=0x1335d78, altdest=altdest@entry=0x1335d78,
completionTag=completionTag@entry=0x7fff8c773240 "") at pquery.c:780
780 if (completionTag && portal->commandTag)
Value returned is $48 = 10
(gdb) finish
Run till exit from #0 PortalRun (portal=portal@entry=0x1373f50, count=count@entry=9223372036854775807,
isTopLevel=isTopLevel@entry=true, run_once=run_once@entry=true, dest=dest@entry=0x1335d78, altdest=altdest@entry=0x1335d78,
completionTag=completionTag@entry=0x7fff8c773240 "") at pquery.c:780
exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1130
1130 receiver->rDestroy(receiver);
Value returned is $49 = true
(gdb) finish
Run till exit from #0 exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1130

Breakpoint 7, postgresEndForeignScan (node=0x13bf120) at postgres_fdw.c:1515
1515 {
(gdb) bt
#0 postgresEndForeignScan (node=0x13bf120) at postgres_fdw.c:1515
#1 0x0000000000619173 in ExecEndForeignScan (node=0x13bf120) at nodeForeignscan.c:249
#2 0x00000000005f16ad in ExecEndPlan (estate=0x13bef10, planstate=<optimized out>) at execMain.c:1612
#3 standard_ExecutorEnd (queryDesc=0x1330130) at execMain.c:495
#4 0x00000000005abfc4 in PortalCleanup (portal=<optimized out>) at portalcmds.c:301
#5 0x000000000084445a in PortalDrop (portal=0x1373f50, isTopCommit=<optimized out>) at portalmem.c:499
#6 0x0000000000721bc8 in exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1132
#7 0x0000000000722e62 in PostgresMain (argc=<optimized out>, argv=argv@entry=0x1338568, dbname=0x1338450 "fdw", username=<optimized out>) at postgres.c:4153
#8 0x000000000047a861 in BackendRun (port=0x1330430) at postmaster.c:4361
#9 BackendStartup (port=0x1330430) at postmaster.c:4033
#10 ServerLoop () at postmaster.c:1706
#11 0x00000000006babb9 in PostmasterMain (argc=argc@entry=3, argv=argv@entry=0x13093c0) at postmaster.c:1379
#12 0x000000000047b2a1 in main (argc=3, argv=0x13093c0) at main.c:228
(gdb) finish
Run till exit from #0 postgresEndForeignScan (node=0x13bf120) at postgres_fdw.c:1515
0x0000000000619173 in ExecEndForeignScan (node=0x13bf120) at nodeForeignscan.c:249
249 node->fdwroutine->EndForeignScan(node);
(gdb) finish
Run till exit from #0 0x0000000000619173 in ExecEndForeignScan (node=0x13bf120) at nodeForeignscan.c:249
ExecEndPlan (estate=0x13bef10, planstate=<optimized out>) at execMain.c:1617
1617 foreach(l, estate->es_subplanstates)
(gdb) finish
Run till exit from #0 ExecEndPlan (estate=0x13bef10, planstate=<optimized out>) at execMain.c:1617
498 UnregisterSnapshot(estate->es_snapshot);
(gdb) finish
Run till exit from #0 standard_ExecutorEnd (queryDesc=0x1330130) at execMain.c:498
PortalCleanup (portal=<optimized out>) at portalcmds.c:302
302 FreeQueryDesc(queryDesc);
(gdb) finish
Run till exit from #0 PortalCleanup (portal=<optimized out>) at portalcmds.c:302
PortalDrop (portal=0x1373f50, isTopCommit=<optimized out>) at portalmem.c:500
500 portal->cleanup = NULL;
(gdb) finish
Run till exit from #0 PortalDrop (portal=0x1373f50, isTopCommit=<optimized out>) at portalmem.c:500
exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1134
1134 if (lnext(parsetree_item) == NULL)
(gdb) finish
Run till exit from #0 exec_simple_query (query_string=0x130e810 "select * from t_fdw;") at postgres.c:1134
0x0000000000722e62 in PostgresMain (argc=<optimized out>, argv=argv@entry=0x1338568, dbname=0x1338450 "fdw",
username=<optimized out>) at postgres.c:4153
4153 exec_simple_query(query_string);
(gdb) finish
Run till exit from #0 0x0000000000722e62 in PostgresMain (argc=<optimized out>, argv=argv@entry=0x1338568,
dbname=0x1338450 "fdw", username=<optimized out>) at postgres.c:4153

# 说明,postgresIterateForeignScan一共调用了11次,因为外部表总行数是10行,postgresIterateForeignScan最后一次调用返回NULL,用于结束迭代。
fdw=# insert into t_test values(2,'1');
INSERT 0 1
fdw=# select * from t_fdw;
id | c1 | c2
----+------------+----
1 | 1 | 2
2 | 1 | 2
3 | 1 | 2
4 | 1 | 2
5 | 1 | 2
6 | 1 | 2
7 | 1 | 2
8 | 1 | 2
9 | 1 | 2
10 | 1 | 2
(10 rows)

根据以上的代码跟踪,可以更好的理解实现FDW的7个必须回调函数的调用时机,如果对PostgreSQL的查询机制更加熟悉的话,或许对于如何实现这个7个回调函数跟有帮助。