diff --git a/src/backend/replication/logical/sequencesync.c b/src/backend/replication/logical/sequencesync.c index 717c82328f2..c7cb236f2cb 100644 --- a/src/backend/replication/logical/sequencesync.c +++ b/src/backend/replication/logical/sequencesync.c @@ -60,6 +60,7 @@ #include "replication/logicalworker.h" #include "replication/worker_internal.h" #include "utils/acl.h" +#include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/guc.h" #include "utils/inval.h" @@ -147,13 +148,18 @@ get_sequences_string(List *seqindexes, StringInfo buf) resetStringInfo(buf); foreach_int(seqidx, seqindexes) { + char *qualified_name; + LogicalRepSequenceInfo *seqinfo = (LogicalRepSequenceInfo *) list_nth(seqinfos, seqidx); if (buf->len > 0) appendStringInfoString(buf, ", "); - appendStringInfo(buf, "\"%s.%s\"", seqinfo->nspname, seqinfo->seqname); + qualified_name = quote_qualified_identifier(seqinfo->nspname, + seqinfo->seqname); + appendStringInfoString(buf, qualified_name); + pfree(qualified_name); } } @@ -407,14 +413,23 @@ copy_sequences(WalReceiverConn *conn) for (int idx = cur_batch_base_index; idx < n_seqinfos; idx++) { + char *nsp_literal; + char *seq_literal; + LogicalRepSequenceInfo *seqinfo = (LogicalRepSequenceInfo *) list_nth(seqinfos, idx); if (seqstr->len > 0) appendStringInfoString(seqstr, ", "); - appendStringInfo(seqstr, "(\'%s\', \'%s\', %d)", - seqinfo->nspname, seqinfo->seqname, idx); + nsp_literal = quote_literal_cstr(seqinfo->nspname); + seq_literal = quote_literal_cstr(seqinfo->seqname); + + appendStringInfo(seqstr, "(%s, %s, %d)", + nsp_literal, seq_literal, idx); + + pfree(nsp_literal); + pfree(seq_literal); if (++batch_size == MAX_SEQUENCES_SYNC_PER_BATCH) break; diff --git a/src/test/subscription/t/036_sequences.pl b/src/test/subscription/t/036_sequences.pl index d34b0e4ae2f..50d8f9d6ba5 100644 --- a/src/test/subscription/t/036_sequences.pl +++ b/src/test/subscription/t/036_sequences.pl @@ -32,6 +32,7 @@ $ddl = qq( CREATE SEQUENCE regress_s1; CREATE SEQUENCE regress_s2; CREATE SEQUENCE regress_s3; + CREATE SEQUENCE "regress'quote"; ); $node_subscriber->safe_psql('postgres', $ddl); @@ -201,14 +202,39 @@ $node_subscriber->safe_psql('postgres', # Verify that an error is logged for parameter differences on sequence # ('regress_s4'). $node_subscriber->wait_for_log( - qr/WARNING: ( [A-Z0-9]+:)? mismatched or renamed sequence on subscriber \("public.regress_s4"\)\n.*ERROR: ( [A-Z0-9]+:)? logical replication sequence synchronization failed for subscription "regress_seq_sub"/, + qr/WARNING: ( [A-Z0-9]+:)? mismatched or renamed sequence on subscriber \(.*regress_s4.*\)\n.*ERROR: ( [A-Z0-9]+:)? logical replication sequence synchronization failed for subscription "regress_seq_sub"/, $log_offset); # Verify that an error is logged for the missing sequence ('regress_s4'). $node_publisher->safe_psql('postgres', qq(DROP SEQUENCE regress_s4;)); $node_subscriber->wait_for_log( - qr/WARNING: ( [A-Z0-9]+:)? missing sequence on publisher \("public.regress_s4"\)\n.*ERROR: ( [A-Z0-9]+:)? logical replication sequence synchronization failed for subscription "regress_seq_sub"/, + qr/WARNING: ( [A-Z0-9]+:)? missing sequence on publisher \(.*regress_s4.*\)\n.*ERROR: ( [A-Z0-9]+:)? logical replication sequence synchronization failed for subscription "regress_seq_sub"/, $log_offset); +########## +# Sequences with quotes in the name should be synchronized correctly. +########## + +$node_publisher->safe_psql( + 'postgres', qq( + CREATE SEQUENCE "regress'quote"; + INSERT INTO regress_seq_test + SELECT nextval('"regress''quote"') FROM generate_series(1,100); +)); + +$node_subscriber->safe_psql( + 'postgres', qq( + ALTER SUBSCRIPTION regress_seq_sub REFRESH PUBLICATION; +)); +$node_subscriber->poll_query_until('postgres', $synced_query) + or die "Timed out while waiting for subscriber to synchronize data"; + +$result = $node_subscriber->safe_psql( + 'postgres', qq( + SELECT last_value, is_called FROM "regress'quote"; +)); +is($result, '100|t', + 'REFRESH PUBLICATION will sync sequences with quoted names'); + done_testing();