diff --git a/contrib/test_decoding/expected/ddl.out b/contrib/test_decoding/expected/ddl.out
index 1e22c1eefc..d1feea4909 100644
*** a/contrib/test_decoding/expected/ddl.out
--- b/contrib/test_decoding/expected/ddl.out
***************
*** 543,548 **** UPDATE table_with_unique_not_null SET data = 3 WHERE data = 2;
--- 543,550 ----
UPDATE table_with_unique_not_null SET id = -id;
UPDATE table_with_unique_not_null SET id = -id;
DELETE FROM table_with_unique_not_null WHERE data = 3;
+ TRUNCATE table_with_unique_not_null;
+ TRUNCATE table_with_unique_not_null, table_with_unique_not_null RESTART IDENTITY CASCADE;
-- check toast support
BEGIN;
CREATE SEQUENCE toasttable_rand_seq START 79 INCREMENT 1499; -- portable "random"
***************
*** 660,665 **** SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'inc
--- 662,673 ----
table public.table_with_unique_not_null: DELETE: id[integer]:4
COMMIT
BEGIN
+ table public.table_with_unique_not_null: TRUNCATE: (no-flags)
+ COMMIT
+ BEGIN
+ table public.table_with_unique_not_null: TRUNCATE: restart_seqs cascade
+ COMMIT
+ BEGIN
table public.toasttable: INSERT: id[integer]:1 toasted_col1[text]:'12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000' rand1[double precision]:79 toasted_col2[text]:null rand2[double precision]:1578
COMMIT
BEGIN
***************
*** 668,674 **** SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'inc
BEGIN
table public.toasttable: UPDATE: id[integer]:1 toasted_col1[text]:'12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000' rand1[double precision]:79 toasted_col2[text]:null rand2[double precision]:1578
COMMIT
! (103 rows)
INSERT INTO toasttable(toasted_col1) SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i);
-- update of second column, first column unchanged
--- 676,682 ----
BEGIN
table public.toasttable: UPDATE: id[integer]:1 toasted_col1[text]:'12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000' rand1[double precision]:79 toasted_col2[text]:null rand2[double precision]:1578
COMMIT
! (109 rows)
INSERT INTO toasttable(toasted_col1) SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i);
-- update of second column, first column unchanged
diff --git a/contrib/test_decoding/sql/ddl.sqindex 057dae056b..0fb4102db8 100644
*** a/contrib/test_decoding/sql/ddl.sql
--- b/contrib/test_decoding/sql/ddl.sql
***************
*** 333,338 **** UPDATE table_with_unique_not_null SET id = -id;
--- 333,341 ----
UPDATE table_with_unique_not_null SET id = -id;
DELETE FROM table_with_unique_not_null WHERE data = 3;
+ TRUNCATE table_with_unique_not_null;
+ TRUNCATE table_with_unique_not_null, table_with_unique_not_null RESTART IDENTITY CASCADE;
+
-- check toast support
BEGIN;
CREATE SEQUENCE toasttable_rand_seq START 79 INCREMENT 1499; -- portable "random"
diff --git a/contrib/test_decoding/test_index 0f18afa852..55c4593ed5 100644
*** a/contrib/test_decoding/test_decoding.c
--- b/contrib/test_decoding/test_decoding.c
***************
*** 466,471 **** pg_decode_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
--- 466,485 ----
&change->data.tp.oldtuple->tuple,
true);
break;
+ case REORDER_BUFFER_CHANGE_TRUNCATE:
+ appendStringInfoString(ctx->out, " TRUNCATE:");
+
+ if (change->data.truncate_msg.restart_seqs
+ || change->data.truncate_msg.cascade)
+ {
+ if (change->data.truncate_msg.restart_seqs)
+ appendStringInfo(ctx->out, " restart_seqs");
+ if (change->data.truncate_msg.cascade)
+ appendStringInfo(ctx->out, " cascade");
+ }
+ else
+ appendStringInfoString(ctx->out, " (no-flags)");
+ break;
default:
Assert(false);
}
diff --git a/doc/src/sgml/logical-replicatioindex 75551d8ee1..6b64c8ef76 100644
*** a/doc/src/sgml/logical-replication.sgml
--- b/doc/src/sgml/logical-replication.sgml
***************
*** 111,116 ****
--- 111,118 ----
any combination of INSERT, UPDATE, and
DELETE, similar to how triggers are fired by
particular event types. By default, all operation types are replicated.
+ TRUNCATE is treated as a form of DELETE
+ for the purpose of deciding whether to publish, or not.
***************
*** 364,378 ****
-
-
- TRUNCATE commands are not replicated. This can, of
- course, be worked around by using DELETE instead. To
- avoid accidental TRUNCATE invocations, you can revoke
- the TRUNCATE privilege from tables.
-
-
-
Large objects (see ) are not replicated.
--- 366,371 ----
diff --git a/doc/src/sgml/protocol.sgml b/doindex 4c5ed1e6d6..d2a0d7e52e 100644
*** a/doc/src/sgml/protocol.sgml
--- b/doc/src/sgml/protocol.sgml
***************
*** 6838,6843 **** TupleData
--- 6838,6889 ----
+
+
+ Truncate
+
+
+
+
+
+
+
+ Byte1('T')
+
+
+
+ Identifies the message as a truncate message.
+
+
+
+
+
+ Int32
+
+
+
+ ID of the relation corresponding to the ID in the relation
+ message.
+
+
+
+
+
+ Int8
+
+
+
+ Option flags for truncate. Currently can be 0 for no flags,
+ 1 for CASCADE, 2 for RESTART IDENTITY and 3 if both are set.
+
+
+
+
+
+
+
+
+
diff --git a/doc/src/sgml/ref/creindex bfe12d5f41..c5032938a7 100644
*** a/doc/src/sgml/ref/create_publication.sgml
--- b/doc/src/sgml/ref/create_publication.sgml
***************
*** 111,116 **** CREATE PUBLICATION name
--- 111,121 ----
and so the default value for this option is
'insert, update, delete'.
+
+ TRUNCATE is treated as a form of
+ DELETE for the purpose of deciding whether
+ to publish, or not.
+
***************
*** 168,175 **** CREATE PUBLICATION name
! TRUNCATE and DDL operations
! are not published.
--- 173,179 ----
! DDL operations are not published.
diff --git a/src/backend/access/heap/heapam.c bindex dbc8f2d6c7..f4c6eaf57f 100644
*** a/src/backend/access/heap/heapam.c
--- b/src/backend/access/heap/heapam.c
***************
*** 9134,9139 **** heap_redo(XLogReaderState *record)
--- 9134,9146 ----
case XLOG_HEAP_UPDATE:
heap_xlog_update(record, false);
break;
+ case XLOG_HEAP_TRUNCATE:
+ /*
+ * TRUNCATE is a no-op because the actions are already logged
+ * as SMGR WAL records. TRUNCATE WAL record only exists to allow
+ * it to be logically decoded precisely.
+ */
+ break;
case XLOG_HEAP_HOT_UPDATE:
heap_xlog_update(record, true);
break;
diff --git a/src/backend/access/rmgrdesindex b00c071cb6..15550cdff0 100644
*** a/src/backend/access/rmgrdesc/heapdesc.c
--- b/src/backend/access/rmgrdesc/heapdesc.c
***************
*** 75,80 **** heap_desc(StringInfo buf, XLogReaderState *record)
--- 75,93 ----
xlrec->new_offnum,
xlrec->new_xmax);
}
+ else if (info == XLOG_HEAP_TRUNCATE)
+ {
+ xl_heap_truncate *xlrec = (xl_heap_truncate *) rec;
+
+ if (xlrec->flags & XLH_TRUNCATE_CASCADE)
+ appendStringInfo(buf, "cascade ");
+ if (xlrec->flags & XLH_TRUNCATE_RESTART_SEQS)
+ appendStringInfo(buf, "restart_seqs ");
+ appendStringInfo(buf, "nrelids %u nseqrelids %u",
+ xlrec->nrelids,
+ xlrec->nseqrelids);
+ /* Skip the list of relids and seqrelids */
+ }
else if (info == XLOG_HEAP_CONFIRM)
{
xl_heap_confirm *xlrec = (xl_heap_confirm *) rec;
***************
*** 186,191 **** heap_identify(uint8 info)
--- 199,207 ----
case XLOG_HEAP_HOT_UPDATE | XLOG_HEAP_INIT_PAGE:
id = "HOT_UPDATE+INIT";
break;
+ case XLOG_HEAP_TRUNCATE:
+ id = "TRUNCATE";
+ break;
case XLOG_HEAP_CONFIRM:
id = "HEAP_CONFIRM";
break;
diff --git a/src/backend/commands/tablecmds.cindex 180ebd0717..8355c4c5c7 100644
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 16,21 ****
--- 16,22 ----
#include "access/genam.h"
#include "access/heapam.h"
+ #include "access/heapam_xlog.h"
#include "access/multixact.h"
#include "access/reloptions.h"
#include "access/relscan.h"
***************
*** 1248,1258 **** ExecuteTruncate(TruncateStmt *stmt)
{
List *rels = NIL;
List *relids = NIL;
! List *seq_relids = NIL;
! EState *estate;
! ResultRelInfo *resultRelInfos;
! ResultRelInfo *resultRelInfo;
! SubTransactionId mySubid;
ListCell *cell;
/*
--- 1249,1255 ----
{
List *rels = NIL;
List *relids = NIL;
! List *relids_logged = NIL;
ListCell *cell;
/*
***************
*** 1276,1281 **** ExecuteTruncate(TruncateStmt *stmt)
--- 1273,1281 ----
truncate_check_rel(rel);
rels = lappend(rels, rel);
relids = lappend_oid(relids, myrelid);
+ /* Log this relation only if needed for logical decoding */
+ if (RelationIsLogicallyLogged(rel))
+ relids_logged = lappend_oid(relids_logged, myrelid);
if (recurse)
{
***************
*** 1296,1301 **** ExecuteTruncate(TruncateStmt *stmt)
--- 1296,1304 ----
truncate_check_rel(rel);
rels = lappend(rels, rel);
relids = lappend_oid(relids, childrelid);
+ /* Log this relation only if needed for logical decoding */
+ if (RelationIsLogicallyLogged(rel))
+ relids_logged = lappend_oid(relids_logged, childrelid);
}
}
else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
***************
*** 1305,1311 **** ExecuteTruncate(TruncateStmt *stmt)
--- 1308,1336 ----
errhint("Do not specify the ONLY keyword, or use truncate only on the partitions directly.")));
}
+ ExecuteTruncateGuts(rels, relids, relids_logged,
+ stmt->behavior, stmt->restart_seqs);
+ }
+
+ void
+ ExecuteTruncateGuts(List *rels, List *relids, List *relids_logged,
+ DropBehavior behavior, bool restart_seqs)
+ {
+ List *seq_relids = NIL;
+ EState *estate;
+ ResultRelInfo *resultRelInfos;
+ ResultRelInfo *resultRelInfo;
+ SubTransactionId mySubid;
+ ListCell *cell;
+ List *seq_relids_logged = NIL;
+ uint32 nrelids = 0;
+ uint32 nseqrelids = 0;
+ uint32 maxrelids = 2;
+ Oid *logrelids = NULL;
+
/*
+ * Open, exclusive-lock, and check all the explicitly-specified relations
+ *
* In CASCADE mode, suck in all referencing relations as well. This
* requires multiple iterations to find indirectly-dependent relations. At
* each phase, we need to exclusive-lock new rels before looking for their
***************
*** 1313,1319 **** ExecuteTruncate(TruncateStmt *stmt)
* soon as we open it, to avoid a faux pas such as holding lock for a long
* time on a rel we have no permissions for.
*/
! if (stmt->behavior == DROP_CASCADE)
{
for (;;)
{
--- 1338,1344 ----
* soon as we open it, to avoid a faux pas such as holding lock for a long
* time on a rel we have no permissions for.
*/
! if (behavior == DROP_CASCADE)
{
for (;;)
{
***************
*** 1335,1340 **** ExecuteTruncate(TruncateStmt *stmt)
--- 1360,1368 ----
truncate_check_rel(rel);
rels = lappend(rels, rel);
relids = lappend_oid(relids, relid);
+ /* Log this relation only if needed for logical decoding */
+ if (RelationIsLogicallyLogged(rel))
+ relids_logged = lappend_oid(relids_logged, relid);
}
}
}
***************
*** 1354,1360 **** ExecuteTruncate(TruncateStmt *stmt)
#ifdef USE_ASSERT_CHECKING
heap_truncate_check_FKs(rels, false);
#else
! if (stmt->behavior == DROP_RESTRICT)
heap_truncate_check_FKs(rels, false);
#endif
}
--- 1382,1388 ----
#ifdef USE_ASSERT_CHECKING
heap_truncate_check_FKs(rels, false);
#else
! if (behavior == DROP_RESTRICT)
heap_truncate_check_FKs(rels, false);
#endif
}
***************
*** 1365,1371 **** ExecuteTruncate(TruncateStmt *stmt)
* We want to do this early since it's pointless to do all the truncation
* work only to fail on sequence permissions.
*/
! if (stmt->restart_seqs)
{
foreach(cell, rels)
{
--- 1393,1399 ----
* We want to do this early since it's pointless to do all the truncation
* work only to fail on sequence permissions.
*/
! if (restart_seqs)
{
foreach(cell, rels)
{
***************
*** 1386,1391 **** ExecuteTruncate(TruncateStmt *stmt)
--- 1414,1423 ----
RelationGetRelationName(seq_rel));
seq_relids = lappend_oid(seq_relids, seq_relid);
+ /* Log this relation only if needed for logical decoding */
+ if (RelationIsLogicallyLogged(seq_rel))
+ seq_relids_logged = lappend_oid(seq_relids_logged,
+ seq_relid);
relation_close(seq_rel, NoLock);
}
***************
*** 1520,1525 **** ExecuteTruncate(TruncateStmt *stmt)
--- 1552,1611 ----
ResetSequence(seq_relid);
}
+ /*
+ * Write a WAL record to allow this set of actions to be logically decoded.
+ * We could optimize this away when !RelationIsLogicallyLogged(rel)
+ * but that doesn't save much space or time.
+ *
+ * Assemble an array of relids, then an array of seqrelids so we can write
+ * a single WAL record for the whole action.
+ */
+ logrelids = palloc(maxrelids * sizeof(Oid));
+ foreach (cell, relids_logged)
+ {
+ nrelids++;
+ if (nrelids > maxrelids)
+ {
+ maxrelids *= 2;
+ logrelids = repalloc(logrelids, maxrelids * sizeof(Oid));
+ }
+ logrelids[nrelids - 1] = lfirst_oid(cell);
+ }
+
+ foreach (cell, seq_relids_logged)
+ {
+ nseqrelids++;
+ if ((nrelids + nseqrelids) > maxrelids)
+ {
+ maxrelids *= 2;
+ logrelids = repalloc(logrelids, maxrelids * sizeof(Oid));
+ }
+ logrelids[nrelids + nseqrelids - 1] = lfirst_oid(cell);
+ }
+
+ if ((nrelids + nseqrelids) > 0)
+ {
+ xl_heap_truncate xlrec;
+
+ xlrec.dbId = MyDatabaseId;
+ xlrec.nrelids = nrelids;
+ xlrec.nseqrelids = nseqrelids;
+ xlrec.flags = 0;
+ if (behavior == DROP_CASCADE)
+ xlrec.flags |= XLH_TRUNCATE_CASCADE;
+ if (restart_seqs)
+ xlrec.flags |= XLH_TRUNCATE_RESTART_SEQS;
+
+ XLogBeginInsert();
+ XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
+ XLogRegisterData((char *) logrelids,
+ (nrelids + nseqrelids) * sizeof(Oid));
+
+ XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
+
+ (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
+ }
+
/*
* Process all AFTER STATEMENT TRUNCATE triggers.
*/
diff --git a/src/backend/replication/loindex 537eba7875..d8408e154c 100644
*** a/src/backend/replication/logical/decode.c
--- b/src/backend/replication/logical/decode.c
***************
*** 65,70 **** static void DecodeLogicalMsgOp(LogicalDecodingContext *ctx, XLogRecordBuffer *bu
--- 65,71 ----
static void DecodeInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
static void DecodeUpdate(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
static void DecodeDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
+ static void DecodeTruncate(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
static void DecodeMultiInsert(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
static void DecodeSpecConfirm(LogicalDecodingContext *ctx, XLogRecordBuffer *buf);
***************
*** 435,440 **** DecodeHeapOp(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
--- 436,446 ----
DecodeDelete(ctx, buf);
break;
+ case XLOG_HEAP_TRUNCATE:
+ if (SnapBuildProcessChange(builder, xid, buf->origptr))
+ DecodeTruncate(ctx, buf);
+ break;
+
case XLOG_HEAP_INPLACE:
/*
***************
*** 805,810 **** DecodeDelete(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
--- 811,856 ----
ReorderBufferQueueChange(ctx->reorder, XLogRecGetXid(r), buf->origptr, change);
}
+ /*
+ * Parse XLOG_HEAP_TRUNCATE from wal
+ */
+ static void
+ DecodeTruncate(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
+ {
+ XLogReaderState *r = buf->record;
+ xl_heap_truncate *xlrec;
+ ReorderBufferChange *change;
+ int i;
+
+ xlrec = (xl_heap_truncate *) XLogRecGetData(r);
+
+ /* only interested in our database */
+ if (xlrec->dbId != ctx->slot->data.database)
+ return;
+
+ /* output plugin doesn't look for this origin, no need to queue */
+ if (FilterByOrigin(ctx, XLogRecGetOrigin(r)))
+ return;
+
+ change = ReorderBufferGetChange(ctx->reorder);
+ change->action = REORDER_BUFFER_CHANGE_TRUNCATE;
+ change->origin_id = XLogRecGetOrigin(r);
+ if (xlrec->flags & XLH_TRUNCATE_CASCADE)
+ change->data.truncate_msg.cascade = true;
+ if (xlrec->flags & XLH_TRUNCATE_RESTART_SEQS)
+ change->data.truncate_msg.restart_seqs = true;
+
+ /*
+ * Queue up one change per relation, ignoring sequences for now
+ */
+ for (i = 0; i < xlrec->nrelids; i++)
+ {
+ change->data.truncate_msg.relid = xlrec->relids[i];
+ ReorderBufferQueueChange(ctx->reorder, XLogRecGetXid(r),
+ buf->origptr, change);
+ }
+ }
+
/*
* Decode XLOG_HEAP2_MULTI_INSERT_insert record into multiple tuplebufs.
*
diff --git a/src/backend/replication/logical/prindex 948343e4ae..2fa6f8393d 100644
*** a/src/backend/replication/logical/proto.c
--- b/src/backend/replication/logical/proto.c
***************
*** 26,31 ****
--- 26,34 ----
*/
#define LOGICALREP_IS_REPLICA_IDENTITY 1
+ #define TRUNCATE_CASCADE (1<<0)
+ #define TRUNCATE_RESTART_SEQS (1<<1)
+
static void logicalrep_write_attrs(StringInfo out, Relation rel);
static void logicalrep_write_tuple(StringInfo out, Relation rel,
HeapTuple tuple);
***************
*** 292,297 **** logicalrep_read_delete(StringInfo in, LogicalRepTupleData *oldtup)
--- 295,342 ----
return relid;
}
+ /*
+ * Write TRUNCATE to the output stream.
+ */
+ void
+ logicalrep_write_truncate(StringInfo out, Relation rel,
+ bool cascade, bool restart_seqs)
+ {
+ uint8 flags = 0;
+
+ pq_sendbyte(out, 'T'); /* action TRUNCATE */
+
+ /* use Oid as relation identifier */
+ pq_sendint32(out, RelationGetRelid(rel));
+
+ /* encode and send truncate flags */
+ if (cascade)
+ flags |= TRUNCATE_CASCADE;
+ if (restart_seqs)
+ flags |= TRUNCATE_RESTART_SEQS;
+ pq_sendint8(out, flags);
+ }
+
+ /*
+ * Read TRUNCATE from stream.
+ */
+ LogicalRepRelId
+ logicalrep_read_truncate(StringInfo in, bool *cascade, bool *restart_seqs)
+ {
+ LogicalRepRelId relid;
+ uint8 flags;
+
+ /* read the relation id */
+ relid = pq_getmsgint(in, 4);
+
+ /* read and decode truncate flags */
+ flags = pq_getmsgint(in, 1);
+ *cascade = (flags & TRUNCATE_CASCADE) > 0;
+ *restart_seqs = (flags & TRUNCATE_RESTART_SEQS) > 0;
+
+ return relid;
+ }
+
/*
* Write relation description to the output stream.
*/
diff --git a/src/backend/replication/logical/rindex 1208da2972..fc7350358a 100644
*** a/src/backend/replication/logical/reorderbuffer.c
--- b/src/backend/replication/logical/reorderbuffer.c
***************
*** 403,408 **** ReorderBufferReturnChange(ReorderBuffer *rb, ReorderBufferChange *change)
--- 403,410 ----
case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:
case REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID:
break;
+ case REORDER_BUFFER_CHANGE_TRUNCATE:
+ break;
}
pfree(change);
***************
*** 1342,1347 **** ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid,
--- 1344,1356 ----
switch (change->action)
{
+ case REORDER_BUFFER_CHANGE_TRUNCATE:
+ reloid = change->data.truncate_msg.relid;
+ relation = RelationIdGetRelation(reloid);
+ rb->apply_change(rb, txn, relation, change);
+ RelationClose(relation);
+ break;
+
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM:
/*
***************
*** 2239,2244 **** ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
--- 2248,2254 ----
}
break;
}
+ case REORDER_BUFFER_CHANGE_TRUNCATE:
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM:
case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:
case REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID:
***************
*** 2524,2529 **** ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
--- 2534,2540 ----
break;
}
/* the base struct contains all the data, easy peasy */
+ case REORDER_BUFFER_CHANGE_TRUNCATE:
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM:
case REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID:
case REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID:
diff --git a/src/backend/replication/logical/worker.c index 83c69092ae..a31b859cb8 100644
*** a/src/backend/replication/logical/worker.c
--- b/src/backend/replication/logical/worker.c
***************
*** 869,874 **** apply_handle_delete(StringInfo s)
--- 869,922 ----
CommandCounterIncrement();
}
+ /*
+ * Handle TRUNCATE message.
+ *
+ * TODO: FDW support
+ */
+ static void
+ apply_handle_truncate(StringInfo s)
+ {
+ LogicalRepRelMapEntry *rel;
+ LogicalRepRelId relid;
+ bool cascade = false;
+ bool restart_seqs = false;
+ List *rels = NIL;
+ List *relids = NIL;
+
+ ensure_transaction();
+
+ relid = logicalrep_read_truncate(s, &cascade, &restart_seqs);
+ rel = logicalrep_rel_open(relid, RowExclusiveLock);
+ if (!should_apply_changes_for_rel(rel))
+ {
+ /*
+ * The relation can't become interesting in the middle of the
+ * transaction so it's safe to unlock it.
+ */
+ logicalrep_rel_close(rel, RowExclusiveLock);
+ return;
+ }
+
+ /* Check if we can do the truncate. */
+ check_relation_updatable(rel);
+
+ rels = lappend(rels, rel->localrel);
+ relids = lappend_oid(relids, rel->localreloid);
+
+ ExecuteTruncateGuts(rels, relids, NULL,
+ cascade ? DROP_CASCADE : DROP_RESTRICT,
+ restart_seqs);
+
+ /* logicalrep_rel_close call not needed, because ExecuteTruncateGuts
+ * already closes the relations. Setting localrel to NULL in the map entry
+ * is still needed.
+ */
+ rel->localrel = NULL;
+
+ CommandCounterIncrement();
+ }
+
/*
* Logical replication protocol message dispatcher.
***************
*** 900,905 **** apply_dispatch(StringInfo s)
--- 948,957 ----
case 'D':
apply_handle_delete(s);
break;
+ /* TRUNCATE */
+ case 'T':
+ apply_handle_truncate(s);
+ break;
/* RELATION */
case 'R':
apply_handle_relation(s);
diff --git a/src/backend/replication/pgoutput/pindex 40a1ef3c1d..7fbd0a3dca 100644
*** a/src/backend/replication/pgoutput/pgoutput.c
--- b/src/backend/replication/pgoutput/pgoutput.c
***************
*** 275,280 **** pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
--- 275,281 ----
if (!relentry->pubactions.pubupdate)
return;
break;
+ case REORDER_BUFFER_CHANGE_TRUNCATE:
case REORDER_BUFFER_CHANGE_DELETE:
if (!relentry->pubactions.pubdelete)
return;
***************
*** 352,357 **** pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn,
--- 353,367 ----
else
elog(DEBUG1, "didn't send DELETE change because of missing oldtuple");
break;
+ case REORDER_BUFFER_CHANGE_TRUNCATE:
+ {
+ OutputPluginPrepareWrite(ctx, true);
+ logicalrep_write_truncate(ctx->out, relation,
+ change->data.truncate_msg.cascade,
+ change->data.truncate_msg.restart_seqs);
+ OutputPluginWrite(ctx, true);
+ }
+ break;
default:
Assert(false);
}
diff --git a/src/include/access/heapam_xlog.h b/srindex 700e25c36a..c56b200f7d 100644
*** a/src/include/access/heapam_xlog.h
--- b/src/include/access/heapam_xlog.h
***************
*** 32,38 ****
#define XLOG_HEAP_INSERT 0x00
#define XLOG_HEAP_DELETE 0x10
#define XLOG_HEAP_UPDATE 0x20
! /* 0x030 is free, was XLOG_HEAP_MOVE */
#define XLOG_HEAP_HOT_UPDATE 0x40
#define XLOG_HEAP_CONFIRM 0x50
#define XLOG_HEAP_LOCK 0x60
--- 32,38 ----
#define XLOG_HEAP_INSERT 0x00
#define XLOG_HEAP_DELETE 0x10
#define XLOG_HEAP_UPDATE 0x20
! #define XLOG_HEAP_TRUNCATE 0x30
#define XLOG_HEAP_HOT_UPDATE 0x40
#define XLOG_HEAP_CONFIRM 0x50
#define XLOG_HEAP_LOCK 0x60
***************
*** 109,114 **** typedef struct xl_heap_delete
--- 109,136 ----
#define SizeOfHeapDelete (offsetof(xl_heap_delete, flags) + sizeof(uint8))
+ /*
+ * xl_heap_delete flag values, 8 bits are available.
+ */
+ #define XLH_TRUNCATE_CASCADE (1<<0)
+ #define XLH_TRUNCATE_RESTART_SEQS (1<<1)
+
+ /*
+ * For truncate we list all truncated relids in an array, followed by all
+ * sequence relids that need to be restarted, if any.
+ * All rels are always within the same database, so we just list dbid once.
+ */
+ typedef struct xl_heap_truncate
+ {
+ Oid dbId;
+ uint32 nrelids;
+ uint32 nseqrelids;
+ uint8 flags;
+ Oid relids[FLEXIBLE_ARRAY_MEMBER];
+ } xl_heap_truncate;
+
+ #define SizeOfHeapTruncate (offsetof(xl_heap_truncate, relids))
+
/*
* We don't store the whole fixed part (HeapTupleHeaderData) of an inserted
* or updated tuple in WAL; we can save a few bytes by reconstructing the
diff --git a/src/include/executor/execuindex a782fae0f8..62ed488442 100644
*** a/src/include/executor/executor.h
--- b/src/include/executor/executor.h
***************
*** 556,559 **** extern void CheckCmdReplicaIdentity(Relation rel, CmdType cmd);
--- 556,565 ----
extern void CheckSubscriptionRelkind(char relkind, const char *nspname,
const char *relname);
+ /*
+ * prototype for tablecmds.c accessible for logical apply
+ */
+ void ExecuteTruncateGuts(List *rels, List *relids, List *relids_logged,
+ DropBehavior behavior, bool restart_seqs);
+
#endif /* EXECUTOR_H */
diff --git a/src/include/replication/lindex 0eb21057c5..b1abb9e36f 100644
*** a/src/include/replication/logicalproto.h
--- b/src/include/replication/logicalproto.h
***************
*** 98,103 **** extern void logicalrep_write_delete(StringInfo out, Relation rel,
--- 98,107 ----
HeapTuple oldtuple);
extern LogicalRepRelId logicalrep_read_delete(StringInfo in,
LogicalRepTupleData *oldtup);
+ extern void logicalrep_write_truncate(StringInfo out, Relation rel,
+ bool cascade, bool restart_seqs);
+ extern LogicalRepRelId logicalrep_read_truncate(StringInfo in,
+ bool *cascade, bool *restart_seqs);
extern void logicalrep_write_rel(StringInfo out, Relation rel);
extern LogicalRepRelation *logicalrep_read_rel(StringInfo in);
extern void logicalrep_write_typ(StringInfo out, Oid typoid);
diff --git a/src/include/replication/reorderbindex 0970abca52..e8439fac49 100644
*** a/src/include/replication/reorderbuffer.h
--- b/src/include/replication/reorderbuffer.h
***************
*** 59,65 **** enum ReorderBufferChangeType
REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID,
REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID,
REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT,
! REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM
};
/*
--- 59,66 ----
REORDER_BUFFER_CHANGE_INTERNAL_COMMAND_ID,
REORDER_BUFFER_CHANGE_INTERNAL_TUPLECID,
REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT,
! REORDER_BUFFER_CHANGE_INTERNAL_SPEC_CONFIRM,
! REORDER_BUFFER_CHANGE_TRUNCATE
};
/*
***************
*** 128,134 **** typedef struct ReorderBufferChange
CommandId cmax;
CommandId combocid;
} tuplecid;
! } data;
/*
* While in use this is how a change is linked into a transactions,
--- 129,146 ----
CommandId cmax;
CommandId combocid;
} tuplecid;
!
! /*
! * Truncate data for REORDER_BUFFER_CHANGE_TRUNCATE representing
! * one relation to be truncated.
! */
! struct
! {
! Oid relid;
! bool cascade;
! bool restart_seqs;
! } truncate_msg;
! } data;
/*
* While in use this is how a change is linked into a transactions,
diff --git a/src/test/subscription/t/001_rep_cindex 0136c79d4b..974e88821c 100644
*** a/src/test/subscription/t/001_rep_changes.pl
--- b/src/test/subscription/t/001_rep_changes.pl
***************
*** 3,9 **** use strict;
use warnings;
use PostgresNode;
use TestLib;
! use Test::More tests => 16;
# Initialize publisher node
my $node_publisher = get_new_node('publisher');
--- 3,9 ----
use warnings;
use PostgresNode;
use TestLib;
! use Test::More tests => 24;
# Initialize publisher node
my $node_publisher = get_new_node('publisher');
***************
*** 189,199 **** $result = $node_subscriber->safe_psql('postgres',
is($result, qq(20|-20|-1),
'check changes skipped after subscription publication change');
# check alter publication (relcache invalidation etc)
$node_publisher->safe_psql('postgres',
"ALTER PUBLICATION tap_pub_ins_only SET (publish = 'insert, delete')");
$node_publisher->safe_psql('postgres',
! "ALTER PUBLICATION tap_pub_ins_only ADD TABLE tab_full");
$node_publisher->safe_psql('postgres', "DELETE FROM tab_ins WHERE a > 0");
$node_subscriber->safe_psql('postgres',
"ALTER SUBSCRIPTION tap_sub REFRESH PUBLICATION WITH (copy_data = false)"
--- 189,210 ----
is($result, qq(20|-20|-1),
'check changes skipped after subscription publication change');
+ # truncate should not be replicated
+ $node_publisher->safe_psql('postgres', "TRUNCATE tab_rep");
+
+ $node_publisher->poll_query_until('postgres', $caughtup_query)
+ or die "Timed out while waiting for subscriber to catch up";
+
+ $result = $node_subscriber->safe_psql('postgres',
+ "SELECT count(*), min(a), max(a) FROM tab_rep");
+ is($result, qq(20|-20|-1),
+ 'check changes skipped after subscription publication change');
+
# check alter publication (relcache invalidation etc)
$node_publisher->safe_psql('postgres',
"ALTER PUBLICATION tap_pub_ins_only SET (publish = 'insert, delete')");
$node_publisher->safe_psql('postgres',
! "ALTER PUBLICATION tap_pub_ins_only ADD TABLE tab_full, tab_rep");
$node_publisher->safe_psql('postgres', "DELETE FROM tab_ins WHERE a > 0");
$node_subscriber->safe_psql('postgres',
"ALTER SUBSCRIPTION tap_sub REFRESH PUBLICATION WITH (copy_data = false)"
***************
*** 213,218 **** $result = $node_subscriber->safe_psql('postgres',
--- 224,295 ----
"SELECT count(*), min(a), max(a) FROM tab_full");
is($result, qq(21|0|100), 'check replicated insert after alter publication');
+ # add a sequence and a foreign key to check cascade and restart
+ # identity truncate options
+ $node_subscriber->safe_psql('postgres',
+ "CREATE TABLE tab_notrep_fk (a int REFERENCES tab_rep(a))"
+ );
+ $node_subscriber->safe_psql('postgres', "INSERT INTO tab_notrep_fk VALUES (-1)");
+ $node_subscriber->safe_psql('postgres',
+ "CREATE SEQUENCE seq_notrep OWNED BY tab_rep.a"
+ );
+ $node_subscriber->safe_psql('postgres',
+ "ALTER SEQUENCE seq_notrep START 101"
+ );
+
+ # truncate should now be replicated
+ $node_publisher->safe_psql('postgres', "TRUNCATE tab_rep");
+
+ $node_publisher->poll_query_until('postgres', $caughtup_query)
+ or die "Timed out while waiting for subscriber to catch up";
+
+ $result = $node_subscriber->safe_psql('postgres',
+ "SELECT count(*), min(a), max(a) FROM tab_rep");
+ is($result, qq(0||),
+ 'check replicated truncate after alter publication');
+
+ $result = $node_subscriber->safe_psql('postgres',
+ "SELECT count(*), min(a), max(a) FROM tab_notrep_fk");
+ is($result, qq(1|-1|-1),
+ 'check replicated truncate does not cascade');
+
+ $result = $node_subscriber->safe_psql('postgres',
+ "SELECT nextval('seq_notrep')");
+ is($result, qq(1),
+ 'check replicated truncate does not restart identities');
+
+ # should restart identity
+ $node_publisher->safe_psql('postgres', "TRUNCATE tab_rep RESTART IDENTITY");
+
+ $node_publisher->poll_query_until('postgres', $caughtup_query)
+ or die "Timed out while waiting for subscriber to catch up";
+
+ $result = $node_subscriber->safe_psql('postgres',
+ "SELECT count(*), min(a), max(a) FROM tab_notrep_fk");
+ is($result, qq(1|-1|-1),
+ 'check replicated truncate does not cascade');
+
+ $result = $node_subscriber->safe_psql('postgres',
+ "SELECT nextval('seq_notrep')");
+ is($result, qq(101),
+ 'check replicated truncate restart identities');
+
+ # should cascade
+ $node_publisher->safe_psql('postgres', "TRUNCATE tab_rep CASCADE");
+
+ $node_publisher->poll_query_until('postgres', $caughtup_query)
+ or die "Timed out while waiting for subscriber to catch up";
+
+ $result = $node_subscriber->safe_psql('postgres',
+ "SELECT count(*), min(a), max(a) FROM tab_notrep_fk");
+ is($result, qq(0||),
+ 'check replicated truncate cascade');
+
+ $result = $node_subscriber->safe_psql('postgres',
+ "SELECT nextval('seq_notrep')");
+ is($result, qq(102),
+ 'check replicated truncate does not restart identities');
+
# check restart on rename
$oldpid = $node_publisher->safe_psql('postgres',
"SELECT pid FROM pg_stat_replication WHERE application_name = '$appname';"