4
4
* Routines to preprocess the parse tree target list
5
5
*
6
6
* For INSERT and UPDATE queries, the targetlist must contain an entry for
7
- * each attribute of the target relation in the correct order. For UPDATE and
8
- * DELETE queries, it must also contain a junk tlist entry needed to allow the
9
- * executor to identify the physical locations of the rows to be updated or
10
- * deleted. For all query types, we may need to add junk tlist entries for
11
- * Vars used in the RETURNING list and row ID information needed for SELECT
12
- * FOR UPDATE locking and/or EvalPlanQual checking.
7
+ * each attribute of the target relation in the correct order. For all query
8
+ * types, we may need to add junk tlist entries for Vars used in the RETURNING
9
+ * list and row ID information needed for SELECT FOR UPDATE locking and/or
10
+ * EvalPlanQual checking.
13
11
*
14
- * The rewriter's rewriteTargetListIU routine also does preprocessing of the
15
- * targetlist. The division of labor between here and there is partially
16
- * historical, but it's not entirely arbitrary. In particular, consider an
17
- * UPDATE across an inheritance tree. What the rewriter does need be done
18
- * only once (because it depends only on the properties of the parent
19
- * relation). What's done here has to be done over again for each child
20
- * relation, because it depends on the column list of the child, which might
21
- * have more columns and/or a different column order than the parent.
12
+ * The rewriter's rewriteTargetListIU and rewriteTargetListUD routines
13
+ * also do preprocessing of the targetlist. The division of labor between
14
+ * here and there is partially historical, but it's not entirely arbitrary.
15
+ * In particular, consider an UPDATE across an inheritance tree. What the
16
+ * rewriter does need be done only once (because it depends only on the
17
+ * properties of the parent relation). What's done here has to be done over
18
+ * again for each child relation, because it depends on the column list of
19
+ * the child, which might have more columns and/or a different column order
20
+ * than the parent.
22
21
*
23
22
* The fact that rewriteTargetListIU sorts non-resjunk tlist entries by column
24
23
* position, which expand_targetlist depends on, violates the above comment
42
41
#include "access/heapam.h"
43
42
#include "access/sysattr.h"
44
43
#include "catalog/pg_type.h"
45
- #include "foreign/fdwapi.h"
46
44
#include "nodes/makefuncs.h"
47
- #include "optimizer/clauses.h"
48
45
#include "optimizer/prep.h"
49
46
#include "optimizer/tlist.h"
50
47
#include "optimizer/var.h"
55
52
56
53
static List * expand_targetlist (List * tlist ,int command_type ,
57
54
Index result_relation ,List * range_table );
58
- static void rewrite_targetlist (Query * parse ,
59
- Index result_relation ,List * range_table );
60
55
61
56
62
57
/*
@@ -66,13 +61,12 @@ static void rewrite_targetlist(Query *parse,
66
61
* Returns the new targetlist.
67
62
*/
68
63
List *
69
- preprocess_targetlist (PlannerInfo * root )
64
+ preprocess_targetlist (PlannerInfo * root , List * tlist )
70
65
{
71
66
Query * parse = root -> parse ;
72
67
int result_relation = parse -> resultRelation ;
73
68
List * range_table = parse -> rtable ;
74
69
CmdType command_type = parse -> commandType ;
75
- List * tlist ;
76
70
ListCell * lc ;
77
71
78
72
/*
@@ -87,16 +81,6 @@ preprocess_targetlist(PlannerInfo *root)
87
81
elog (ERROR ,"subquery cannot be result relation" );
88
82
}
89
83
90
- /*
91
- * For UPDATE/DELETE, add a necessary junk column needed to allow the
92
- * executor to identify the physical locations of the rows to be updated
93
- * or deleted.
94
- */
95
- if (command_type == CMD_UPDATE || command_type == CMD_DELETE )
96
- rewrite_targetlist (parse ,result_relation ,range_table );
97
-
98
- tlist = parse -> targetList ;
99
-
100
84
/*
101
85
* for heap_form_tuple to work, the targetlist must match the exact order
102
86
* of the attributes. We also need to fill in any missing attributes. -ay
@@ -407,96 +391,6 @@ expand_targetlist(List *tlist, int command_type,
407
391
return new_tlist ;
408
392
}
409
393
410
- /*
411
- * rewrite_targetlist - rewrite UPDATE/DELETE targetlist as needed
412
- *
413
- * This function adds a "junk" TLE that is needed to allow the executor to
414
- * find the original row for the update or delete. When the target relation
415
- * is a regular table, the junk TLE emits the ctid attribute of the original
416
- * row. When the target relation is a foreign table, we let the FDW decide
417
- * what to add.
418
- */
419
- static void
420
- rewrite_targetlist (Query * parse ,Index result_relation ,List * range_table )
421
- {
422
- Var * var = NULL ;
423
- const char * attrname ;
424
- TargetEntry * tle ;
425
- RangeTblEntry * target_rte ;
426
- Relation target_relation ;
427
-
428
- target_rte = rt_fetch (result_relation ,range_table );
429
-
430
- /*
431
- * We assume that the relation was already locked by the rewriter, so
432
- * we need no lock here.
433
- */
434
- target_relation = heap_open (target_rte -> relid ,NoLock );
435
-
436
- if (target_relation -> rd_rel -> relkind == RELKIND_RELATION ||
437
- target_relation -> rd_rel -> relkind == RELKIND_MATVIEW ||
438
- target_relation -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE )
439
- {
440
- /*
441
- * Emit CTID so that executor can find the row to update or delete.
442
- */
443
- var = makeVar (result_relation ,
444
- SelfItemPointerAttributeNumber ,
445
- TIDOID ,
446
- -1 ,
447
- InvalidOid ,
448
- 0 );
449
-
450
- attrname = "ctid" ;
451
- }
452
- else if (target_relation -> rd_rel -> relkind == RELKIND_FOREIGN_TABLE )
453
- {
454
- /*
455
- * Let the foreign table's FDW add whatever junk TLEs it wants.
456
- */
457
- FdwRoutine * fdwroutine ;
458
-
459
- fdwroutine = GetFdwRoutineForRelation (target_relation , false);
460
-
461
- if (fdwroutine -> AddForeignUpdateTargets != NULL )
462
- fdwroutine -> AddForeignUpdateTargets (parse ,target_rte ,
463
- target_relation );
464
-
465
- /*
466
- * If we have a row-level trigger corresponding to the operation, emit
467
- * a whole-row Var so that executor will have the "old" row to pass to
468
- * the trigger. Alas, this misses system columns.
469
- */
470
- if (target_relation -> trigdesc &&
471
- ((parse -> commandType == CMD_UPDATE &&
472
- (target_relation -> trigdesc -> trig_update_after_row ||
473
- target_relation -> trigdesc -> trig_update_before_row ))||
474
- (parse -> commandType == CMD_DELETE &&
475
- (target_relation -> trigdesc -> trig_delete_after_row ||
476
- target_relation -> trigdesc -> trig_delete_before_row ))))
477
- {
478
- var = makeWholeRowVar (target_rte ,
479
- result_relation ,
480
- 0 ,
481
- false);
482
-
483
- attrname = "wholerow" ;
484
- }
485
- }
486
-
487
- if (var != NULL )
488
- {
489
- tle = makeTargetEntry ((Expr * )var ,
490
- list_length (parse -> targetList )+ 1 ,
491
- pstrdup (attrname ),
492
- true);
493
-
494
- parse -> targetList = lappend (parse -> targetList ,tle );
495
- }
496
-
497
- heap_close (target_relation ,NoLock );
498
- }
499
-
500
394
501
395
/*
502
396
* Locate PlanRowMark for given RT index, or return NULL if none