diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2021-06-11 16:12:36 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2021-06-11 16:12:36 -0400 |
commit | b270713fd44b1378cebc3177e092add0155b55b6 (patch) | |
tree | a36bcbf0b58d01fe7cb1b61e702dcfb471f9638f /src/backend/replication/logical/worker.c | |
parent | 218b101008b533156d7e5832fe143d1e04a01301 (diff) |
Fix multiple crasher bugs in partitioned-table replication logic.
apply_handle_tuple_routing(), having detected and reported that
the tuple it needed to update didn't exist, tried to update that
tuple anyway, leading to a null-pointer dereference.
logicalrep_partition_open() failed to ensure that the
LogicalRepPartMapEntry it built for a partition was fully
independent of that for the partition root, leading to
trouble if the root entry was later freed or rebuilt.
Meanwhile, on the publisher's side, pgoutput_change() sometimes
attempted to apply execute_attr_map_tuple() to a NULL tuple.
The first of these was reported by Sergey Bernikov in bug #17055;
I found the other two while developing some test cases for this
sadly under-tested code.
Diagnosis and patch for the first issue by Amit Langote; patches
for the others by me; new test cases by me. Back-patch to v13
where this logic came in.
Discussion: https://postgr.es/m/17055-9ba800ec8522668b@postgresql.org
Diffstat (limited to 'src/backend/replication/logical/worker.c')
-rw-r--r-- | src/backend/replication/logical/worker.c | 49 |
1 files changed, 28 insertions, 21 deletions
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index eb013c46088..da748668ecc 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -898,12 +898,13 @@ apply_handle_update_internal(ResultRelInfo *relinfo, else { /* - * The tuple to be updated could not be found. + * The tuple to be updated could not be found. Do nothing except for + * emitting a log message. * - * TODO what to do here, change the log level to LOG perhaps? + * XXX should this be promoted to ereport(LOG) perhaps? */ elog(DEBUG1, - "logical replication did not find row for update " + "logical replication did not find row to be updated " "in replication target relation \"%s\"", RelationGetRelationName(localrel)); } @@ -1001,9 +1002,14 @@ apply_handle_delete_internal(ResultRelInfo *relinfo, EState *estate, } else { - /* The tuple to be deleted could not be found. */ + /* + * The tuple to be deleted could not be found. Do nothing except for + * emitting a log message. + * + * XXX should this be promoted to ereport(LOG) perhaps? + */ elog(DEBUG1, - "logical replication could not find row for delete " + "logical replication did not find row to be deleted " "in replication target relation \"%s\"", RelationGetRelationName(localrel)); } @@ -1145,31 +1151,32 @@ apply_handle_tuple_routing(ApplyExecutionData *edata, found = FindReplTupleInLocalRel(estate, partrel, &part_entry->remoterel, remoteslot_part, &localslot); - - oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); - if (found) - { - /* Apply the update. */ - slot_modify_cstrings(remoteslot_part, localslot, - part_entry, - newtup->values, newtup->changed); - MemoryContextSwitchTo(oldctx); - } - else + if (!found) { /* - * The tuple to be updated could not be found. + * The tuple to be updated could not be found. Do nothing + * except for emitting a log message. * - * TODO what to do here, change the log level to LOG - * perhaps? + * XXX should this be promoted to ereport(LOG) perhaps? */ elog(DEBUG1, - "logical replication did not find row for update " - "in replication target relation \"%s\"", + "logical replication did not find row to be updated " + "in replication target relation's partition \"%s\"", RelationGetRelationName(partrel)); + return; } /* + * Apply the update to the local tuple, putting the result in + * remoteslot_part. + */ + oldctx = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + slot_modify_cstrings(remoteslot_part, localslot, + part_entry, + newtup->values, newtup->changed); + MemoryContextSwitchTo(oldctx); + + /* * Does the updated tuple still satisfy the current * partition's constraint? */ |