* the snapshot, rangetable, result-rel info, and external Param info.
* They need their own copies of local state, including a tuple table,
* es_param_exec_vals, etc.
+ *
+ * The ResultRelInfo array management is trickier than it looks. We
+ * create a fresh array for the child but copy all the content from the
+ * parent. This is because it's okay for the child to share any
+ * per-relation state the parent has already created --- but if the child
+ * sets up any ResultRelInfo fields, such as its own junkfilter, that
+ * state must *not* propagate back to the parent. (For one thing, the
+ * pointed-to data is in a memory context that won't last long enough.)
*/
estate->es_direction = ForwardScanDirection;
estate->es_snapshot = parentestate->es_snapshot;
estate->es_plannedstmt = parentestate->es_plannedstmt;
estate->es_junkFilter = parentestate->es_junkFilter;
estate->es_output_cid = parentestate->es_output_cid;
- estate->es_result_relations = parentestate->es_result_relations;
- estate->es_num_result_relations = parentestate->es_num_result_relations;
- estate->es_result_relation_info = parentestate->es_result_relation_info;
+ if (parentestate->es_num_result_relations > 0)
+ {
+ int numResultRelations = parentestate->es_num_result_relations;
+ ResultRelInfo *resultRelInfos;
+
+ resultRelInfos = (ResultRelInfo *)
+ palloc(numResultRelations * sizeof(ResultRelInfo));
+ memcpy(resultRelInfos, parentestate->es_result_relations,
+ numResultRelations * sizeof(ResultRelInfo));
+ estate->es_result_relations = resultRelInfos;
+ estate->es_num_result_relations = numResultRelations;
+ }
+ /* es_result_relation_info must NOT be copied */
/* es_trig_target_relations must NOT be copied */
estate->es_rowMarks = parentestate->es_rowMarks;
estate->es_top_eflags = parentestate->es_top_eflags;
INSERT INTO accounts SELECT 'savings', 500
WHERE NOT EXISTS (SELECT 1 FROM upsert);
}
-# tests with table p check inheritance cases, specifically a bug where
-# nodeLockRows did the wrong thing when the first updated tuple was in
-# a non-first child table
+
+# tests with table p check inheritance cases:
+# readp1/writep1/readp2 tests a bug where nodeLockRows did the wrong thing
+# when the first updated tuple was in a non-first child table.
+# writep2/returningp1 tests a memory allocation issue
+
step "readp1" { SELECT tableoid::regclass, ctid, * FROM p WHERE b IN (0, 1) AND c = 0 FOR UPDATE; }
step "writep1" { UPDATE p SET b = -1 WHERE a = 1 AND b = 1 AND c = 0; }
+step "writep2" { UPDATE p SET b = -b WHERE a = 1 AND c = 0; }
step "c1" { COMMIT; }
session "s2"
WHERE NOT EXISTS (SELECT 1 FROM upsert);
}
step "readp2" { SELECT tableoid::regclass, ctid, * FROM p WHERE b IN (0, 1) AND c = 0 FOR UPDATE; }
+step "returningp1" {
+ WITH u AS ( UPDATE p SET b = b WHERE a > 0 RETURNING * )
+ SELECT * FROM u;
+}
step "c2" { COMMIT; }
session "s3"
permutation "wy1" "wy2" "c1" "c2" "read"
permutation "upsert1" "upsert2" "c1" "c2" "read"
permutation "readp1" "writep1" "readp2" "c1" "c2"
+permutation "writep2" "returningp1" "c1" "c2"