H.3. wal2json â пÑеобÑазование изменений из WAL в JSON Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð»Ð¾Ð³Ð¸ÑеÑкого декодиÑÐ¾Ð²Ð°Ð½Ð¸Ñ #
ÐодÑÐ»Ñ wal2json â ÑÑо ÑаÑÑиÑение Postgres Pro Ð´Ð»Ñ Ð»Ð¾Ð³Ð¸ÑеÑкого декодиÑованиÑ, коÑоÑое пÑеобÑазÑÐµÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð½ÑÑ
из жÑÑнала пÑедзапиÑи (WAL) в ÑоÑÐ¼Ð°Ñ JSON. Postgres Pro Ð¸Ð¼ÐµÐµÑ Ð´Ð¾ÑÑÑп к коÑÑежам, ÑгенеÑиÑованнÑм командами INSERT и UPDATE. РзавиÑимоÑÑи Ð¾Ñ Ð²ÑбоÑа ваÑианÑа иденÑиÑикаÑии Ñеплики Ñакже могÑÑ Ð±ÑÑÑ Ð´Ð¾ÑÑÑÐ¿Ð½Ñ Ð¿ÑедÑдÑÑие веÑÑии ÑÑÑок Ð´Ð»Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ UPDATE и DELETE. ÐÐ·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ полÑÑиÑÑ Ð»Ð¸Ð±Ð¾ по пÑоÑÐ¾ÐºÐ¾Ð»Ñ Ð¿Ð¾Ñоковой ÑепликаÑии (ÑлоÑÑ Ð»Ð¾Ð³Ð¸ÑеÑкой ÑепликаÑии), либо ÑеÑез ÑпеÑиалÑнÑй SQL API.
ФоÑÐ¼Ð°Ñ Ð²ÐµÑÑии 1 ÑоздаÑÑ JSON-обÑÐµÐºÑ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ ÑÑанзакÑии. ÐÑÐ¾Ñ Ð¾Ð±ÑÐµÐºÑ ÑодеÑÐ¶Ð¸Ñ Ð²Ñе новÑе и ÑÑаÑÑе коÑÑежи. Также еÑÑÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ Ð²ÐºÐ»ÑÑиÑÑ Ð² него Ñакие ÑвойÑÑва, как меÑки вÑемени ÑÑанзакÑий, имена, дополненнÑе именами ÑÑ ÐµÐ¼, ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ Ð¸ иденÑиÑикаÑоÑÑ ÑÑанзакÑий.
ФоÑÐ¼Ð°Ñ Ð²ÐµÑÑии 2 ÑоздаÑÑ JSON-обÑÐµÐºÑ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ коÑÑежа Ñ Ð½ÐµÐ¾Ð±ÑзаÑелÑнÑми JSON-обÑекÑами, обознаÑаÑÑими наÑало и ÐºÐ¾Ð½ÐµÑ ÑÑанзакÑии. Также можно вклÑÑиÑÑ ÑазнÑе ÑвойÑÑва ÑÑанзакÑии.
H.3.1. УÑÑановка и наÑÑÑойка #
wal2json поÑÑавлÑеÑÑÑ Ð²Ð¼ÐµÑÑе Ñ Postgres Pro Standard в виде оÑделÑного пакеÑа wal2json-std-17 (подÑобнÑе инÑÑÑÑкÑии по ÑÑÑановке пÑÐ¸Ð²ÐµÐ´ÐµÐ½Ñ Ð² Ðлаве 16). ÐоÑле ÑÑÑановки Postgres Pro Standard вÑполниÑе ÑледÑÑÑие дейÑÑвиÑ, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð´Ð³Ð¾ÑовиÑÑ wal2json к ÑабоÑе:
ÐклÑÑиÑе логиÑеÑкое декодиÑование, задав Ð´Ð»Ñ Ð¿Ð°ÑамеÑÑа
wal_levelзнаÑениеlogicalв Ñайлеpostgresql.conf.ÐополниÑелÑно Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе задаÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¿Ð°ÑамеÑÑов
max_replication_slotsиmax_wal_senders.ÐеÑезапÑÑÑиÑе ÑеÑÐ²ÐµÑ Ð±Ð°Ð· даннÑÑ , ÑÑÐ¾Ð±Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²ÑÑÑпили в ÑилÑ.
H.3.2. ÐаÑамеÑÑÑ #
ÐодÑÐ»Ñ wal2json пÑедоÑÑавлÑÐµÑ ÑазлиÑнÑе паÑамеÑÑÑ Ð´Ð»Ñ ÑпÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ Ð»Ð¾Ð³Ð¸ÑеÑким декодиÑованием:
include-xidsÐобавиÑÑ Ð¸Ð´ÐµÐ½ÑиÑикаÑÐ¾Ñ ÑÑанзакÑии к ÐºÐ°Ð¶Ð´Ð¾Ð¼Ñ Ð½Ð°Ð±Ð¾ÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ в JSON-вÑводе. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ â
off.include-timestampÐобавиÑÑ
timestampк ÐºÐ°Ð¶Ð´Ð¾Ð¼Ñ Ð½Ð°Ð±Ð¾ÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ в JSON-вÑводе. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ âoff.include-schemasÐобавиÑÑ Ð¸Ð¼Ñ ÑÑ ÐµÐ¼Ñ Ðº каждой запиÑи об изменениÑÑ Ð² JSON-вÑводе. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ â
on.include-typesÐобавиÑÑ
typeк каждой запиÑи об изменениÑÑ Ð² JSON-вÑводе. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ âon.include-typmodÐобавиÑÑ Ð¼Ð¾Ð´Ð¸ÑикаÑÐ¾Ñ Ñипа Ð´Ð»Ñ ÑÑолбÑов, Ñ ÐºÐ¾ÑоÑÑÑ Ð¾Ð½Ð¸ еÑÑÑ. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ â
on.include-type-oidsÐобавиÑÑ OID Ñипа. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ â off.
include-domain-data-typeÐамениÑÑ Ð´Ð¾Ð¼ÐµÐ½Ð½Ð¾Ðµ Ð¸Ð¼Ñ Ð½Ð¸Ð¶ÐµÐ»ÐµÐ¶Ð°Ñим Ñипом даннÑÑ . ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ â
off.include-column-positionsÐобавиÑÑ Ð¿Ð¾Ð·Ð¸ÑÐ¸Ñ ÑÑолбÑа (
pg_attribute.attnum). ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ âoff.include-originÐобавиÑÑ Ð¸ÑÑоÑник каждого изменениÑ. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ â
off.include-not-nullÐобавиÑÑ Ð¸Ð½ÑоÑмаÑиÑ, помеÑен ли ÑÑÐ¾Ð»Ð±ÐµÑ ÐºÐ°Ðº
not nullв полеcolumnoptionalsJSON-вÑвода. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ âoff.include-defaultÐобавиÑÑ Ð²ÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾ ÑмолÑÐ°Ð½Ð¸Ñ Ð² JSON-вÑвод. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ â
off.include-pkÐобавиÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ пеÑвиÑном клÑÑе, вклÑÑÐ°Ñ Ð¸Ð¼ÐµÐ½Ð° ÑÑолбÑов и ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ , в поле
pkJSON-вÑвода. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ âoff.numeric-data-types-as-stringÐÑеобÑазоваÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ ÑиÑловÑÑ Ñипов даннÑÑ Ð² ÑÑÑоки в JSON-вÑводе. СпеÑиÑикаÑÐ¸Ñ JSON не поддеÑживаеÑ
InfinityиNaNкак допÑÑÑимÑе ÑиÑловÑе знаÑениÑ. ÐÐ»Ñ ÑиÑел двойной ÑоÑноÑÑи могÑÑ Ð²Ð¾Ð·Ð½Ð¸ÐºÐ½ÑÑÑ Ð¿Ð¾ÑенÑиалÑнÑе пÑÐ¾Ð±Ð»ÐµÐ¼Ñ ÑовмеÑÑимоÑÑи. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ âoff.pretty-printÐобавиÑÑ Ð¿ÑÐ¾Ð±ÐµÐ»Ñ Ð¸ оÑÑÑÑÐ¿Ñ Ð² ÑÑÑÑкÑÑÑÑ JSON-вÑвода. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ â
off.write-in-chunksÐклÑÑиÑÑ Ð·Ð°Ð¿Ð¸ÑÑ JSON-вÑвода неболÑÑими ÑÑагменÑами вмеÑÑо Ñелого набоÑа изменений. ÐÑÐ¾Ñ Ð¿Ð°ÑамеÑÑ Ð¸ÑполÑзÑеÑÑÑ ÑолÑко когда длÑ
format-versionзадано знаÑение1. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ âoff.include-lsnÐобавиÑÑ Ð¿Ð¾Ð»Ðµ
nextlsnк ÐºÐ°Ð¶Ð´Ð¾Ð¼Ñ Ð½Ð°Ð±Ð¾ÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ âoff.include-transactionÐобавиÑÑ Ð·Ð°Ð¿Ð¸Ñи о наÑале и конÑе каждой ÑÑанзакÑии в JSON-вÑвод. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ â
off.filter-originsÐÑклÑÑиÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¸Ð· ÑказаннÑÑ Ð¸ÑÑоÑников. Ðо ÑмолÑÐ°Ð½Ð¸Ñ ÑÑÐ¾Ñ Ð¿Ð°ÑамеÑÑ Ð¿ÑÑÑ, ÑÑо ознаÑаеÑ, ÑÑо иÑÑоÑники не бÑдÑÑ Ð¾ÑÑилÑÑÑованÑ. ÐадаÑÑÑÑ Ð² виде ÑазделÑнного запÑÑÑми ÑпиÑка знаÑений.
filter-tablesÐÑклÑÑиÑÑ ÑÑÑоки из ÑказаннÑÑ ÑаблиÑ. Ðо ÑмолÑÐ°Ð½Ð¸Ñ ÑÑÐ¾Ñ Ð¿Ð°ÑамеÑÑ Ð¿ÑÑÑ, ÑÑо ознаÑаеÑ, ÑÑо ÑаблиÑÑ Ð½Ðµ бÑдÑÑ Ð¾ÑÑилÑÑÑованÑ. ÐадаÑÑÑÑ Ð² виде ÑазделÑнного запÑÑÑми ÑпиÑка знаÑений. Ðмена ÑÐ°Ð±Ð»Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½ÐµÐ½Ñ ÑÑ ÐµÐ¼Ð¾Ð¹. ÐÐ¼Ñ Ð²Ð¸Ð´Ð°
*.fooознаÑÐ°ÐµÑ ÑаблиÑÑfooво вÑÐµÑ ÑÑ ÐµÐ¼Ð°Ñ , а Ð¸Ð¼Ñ Ð²Ð¸Ð´Ð°bar.*ознаÑÐ°ÐµÑ Ð²Ñе ÑаблиÑÑ Ð² ÑÑ ÐµÐ¼Ðµbar. СпеÑиалÑнÑе ÑÐ¸Ð¼Ð²Ð¾Ð»Ñ (пÑобел, одинаÑÐ½Ð°Ñ ÐºÐ°Ð²ÑÑка, запÑÑаÑ, ÑоÑка, звÑздоÑка) Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ ÑкÑаниÑÐ¾Ð²Ð°Ð½Ñ Ð¾Ð±ÑаÑной коÑой ÑеÑÑой. Ð¡Ñ ÐµÐ¼Ð° и ÑаблиÑа ÑÑвÑÑвиÑелÑÐ½Ñ Ðº ÑегиÑÑÑÑ. ÐапÑимеÑ, ÑаблиÑа"public"."Foo bar"должна бÑÑÑ Ñказана какpublic.Foo\ bar.add-tablesÐклÑÑиÑÑ ÑÑÑоки ÑолÑко из ÑказаннÑÑ ÑаблиÑ. Ðо ÑмолÑÐ°Ð½Ð¸Ñ ÑÑÐ¾Ñ Ð¿Ð°ÑамеÑÑ Ð¿ÑÑÑ, ÑÑо ознаÑаеÑ, ÑÑо вклÑÑÐµÐ½Ñ Ð²Ñе ÑаблиÑÑ Ð¸Ð· вÑÐµÑ ÑÑ ÐµÐ¼. ÐÐ»Ñ ÑÑого паÑамеÑÑа дейÑÑвÑÑÑ Ñе же пÑавила, ÑÑо и длÑ
filter-tables.filter-msg-prefixesÐÑклÑÑиÑÑ ÑообÑениÑ, Ñей пÑеÑÐ¸ÐºÑ Ñказан в знаÑении паÑамеÑÑа. Ðо ÑмолÑÐ°Ð½Ð¸Ñ ÑÑÐ¾Ñ Ð¿Ð°ÑамеÑÑ Ð¿ÑÑÑ, ÑÑо ознаÑаеÑ, ÑÑо ÑообÑÐµÐ½Ð¸Ñ Ð½Ðµ бÑдÑÑ Ð¾ÑÑилÑÑÑованÑ. ÐадаÑÑÑÑ Ð² виде ÑазделÑнного запÑÑÑми ÑпиÑка знаÑений.
add-msg-prefixesÐклÑÑиÑÑ ÑолÑко Ñе ÑообÑениÑ, Ñей пÑеÑÐ¸ÐºÑ Ñказан в знаÑении паÑамеÑÑа. Ðо ÑмолÑÐ°Ð½Ð¸Ñ Ð¸ÑполÑзÑÑÑÑÑ Ð²Ñе пÑеÑикÑÑ. ÐадаÑÑÑÑ Ð² виде ÑазделÑнного запÑÑÑми ÑпиÑка знаÑений.
wal2jsonпÑименÑеÑfilter-msg-prefixesдо ÑÑого паÑамеÑÑа.format-versionÐпÑеделиÑÑ, какой ÑоÑÐ¼Ð°Ñ Ð²Ñвода иÑполÑзоваÑÑ. ÐнаÑение по ÑмолÑÐ°Ð½Ð¸Ñ â
1.actionsÐпÑеделиÑÑ, какие опеÑаÑии бÑдÑÑ Ð²ÐºÐ»ÑÑÐµÐ½Ñ Ð² JSON-вÑвод. Ðо ÑмолÑÐ°Ð½Ð¸Ñ Ð¸ÑполÑзÑÑÑÑÑ Ð²Ñе дейÑÑÐ²Ð¸Ñ (
INSERT,UPDATE,DELETEиTRUNCATE). Ðднако, еÑли иÑполÑзÑеÑÑÑformat-version = 1, опеÑаÑиÑTRUNCATEне вклÑÑаеÑÑÑ (в ÑелÑÑ Ð¾Ð±ÑаÑной ÑовмеÑÑимоÑÑи).
H.3.3. ÐÑимеÑÑ #
СÑÑеÑÑвÑÐµÑ Ð´Ð²Ð° ÑпоÑоба полÑÑиÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ (JSON-обÑекÑÑ) в wal2json: ÑеÑез ÑÑнкÑии, вÑзÑваемÑе в SQL или Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ pg_recvlogical.
H.3.3.1. pg_recvlogical #
Ðиже пÑедÑÑавлен пÑимеÑ, как полÑÑиÑÑ JSON-обÑекÑÑ Ð² wal2json Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ pg_recvlogical. Ðомимо вÑÑеÑказанной наÑÑÑойки необÑ
одимо наÑÑÑоиÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑÑение Ð´Ð»Ñ ÑепликаÑии, ÑÑÐ¾Ð±Ñ Ð¸ÑполÑзоваÑÑ pg_recvlogical. ÐаÑÐ¸Ð½Ð°Ñ Ñ Postgres Pro веÑÑии 10, логиÑеÑÐºÐ°Ñ ÑепликаÑÐ¸Ñ ÑопоÑÑавлÑÐµÑ Ð¾Ð±ÑÑнÑе запиÑи Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð½ÑÑ
или клÑÑевÑми Ñловами, Ñакими как all.
ЧÑÐ¾Ð±Ñ Ð½Ð°ÑÑÑоиÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑÑение Ð´Ð»Ñ ÑепликаÑии и паÑамеÑÑÑ Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð½ÑÑ :
ÐобавÑÑе пÑавило подклÑÑÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑепликаÑии в Ñайле
pg_hba.conf:local mydatabase myuser trustÐополниÑелÑно можно задаÑÑ
max_wal_sendersв Ñайлеpostgresql.conf:max_wal_senders = 1ÐеÑезапÑÑÑиÑе ÑеÑÐ²ÐµÑ Ð±Ð°Ð· даннÑÑ , еÑли изменили
max_wal_senders.
ЧÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑиÑÑ JSON-обÑекÑÑ Ð² wal2json:
ÐÑкÑойÑе ÑеÑминал и подклÑÑиÑеÑÑ Ðº базе даннÑÑ :
$ pg_recvlogical -d postgres --slot test_slot --create-slot -P wal2json $ pg_recvlogical -d postgres --slot test_slot --start -o pretty-print=1 -o add-msg-prefixes=wal2json -f -РдÑÑгом ÑеÑминале:
$ cat /tmp/example1.sql CREATE TABLE table1_with_pk (a SERIAL, b VARCHAR(30), c TIMESTAMP NOT NULL, PRIMARY KEY(a, c)); CREATE TABLE table1_without_pk (a SERIAL, b NUMERIC(5,2), c TEXT); BEGIN; INSERT INTO table1_with_pk (b, c) VALUES('Backup and Restore', now()); INSERT INTO table1_with_pk (b, c) VALUES('Tuning', now()); INSERT INTO table1_with_pk (b, c) VALUES('Replication', now()); SELECT pg_logical_emit_message(true, 'wal2json', 'this message will be delivered'); SELECT pg_logical_emit_message(true, 'pgoutput', 'this message will be filtered'); DELETE FROM table1_with_pk WHERE a < 3; SELECT pg_logical_emit_message(false, 'wal2json', 'this non-transactional message will be delivered even if you rollback the transaction'); INSERT INTO table1_without_pk (b, c) VALUES(2.34, 'Tapir'); -- ÑÑа запиÑÑ Ð½Ðµ добавлÑеÑÑÑ Ð² поÑок, Ñак как оÑÑÑÑÑÑвÑÐµÑ Ð¿ÐµÑвиÑнÑй клÑÑ Ð¸Ð»Ð¸ ÑепликаÑионнÑй иденÑиÑикаÑÐ¾Ñ UPDATE table1_without_pk SET c = 'Anta' WHERE c = 'Tapir'; COMMIT; DROP TABLE table1_with_pk; DROP TABLE table1_without_pk; $ psql -At -f /tmp/example1.sql postgres CREATE TABLE CREATE TABLE BEGIN INSERT 0 1 INSERT 0 1 INSERT 0 1 3/78BFC828 3/78BFC880 DELETE 2 3/78BFC990 INSERT 0 1 UPDATE 1 COMMIT DROP TABLE DROP TABLEÐÑвод в пеÑвом ÑеÑминале Ð¼Ð¾Ð¶ÐµÑ Ð²ÑглÑдеÑÑ Ñак:
$ psql -At -f /tmp/example2.sql postgres CREATE TABLE CREATE TABLE init BEGIN INSERT 0 1 INSERT 0 1 INSERT 0 1 3/78C2CA50 3/78C2CAA8 DELETE 2 3/78C2CBD8 INSERT 0 1 UPDATE 1 COMMIT { "change": [ { "kind": "message", "transactional": false, "prefix": "wal2json", "content": "this non-transactional message will be delivered even if you rollback the transaction" } ] } psql:/tmp/example2.sql:17: WARNING: table "table2_without_pk" without primary key or replica identity is nothing { "change": [ { "kind": "insert", "schema": "public", "table": "table2_with_pk", "columnnames": ["a", "b", "c"], "columntypes": ["integer", "character varying(30)", "timestamp without time zone"], "columnvalues": [1, "Backup and Restore", "2018-03-27 12:05:29.914496"] } ,{ "kind": "insert", "schema": "public", "table": "table2_with_pk", "columnnames": ["a", "b", "c"], "columntypes": ["integer", "character varying(30)", "timestamp without time zone"], "columnvalues": [2, "Tuning", "2018-03-27 12:05:29.914496"] } ,{ "kind": "insert", "schema": "public", "table": "table2_with_pk", "columnnames": ["a", "b", "c"], "columntypes": ["integer", "character varying(30)", "timestamp without time zone"], "columnvalues": [3, "Replication", "2018-03-27 12:05:29.914496"] } ,{ "kind": "message", "transactional": true, "prefix": "wal2json", "content": "this message will be delivered" } ,{ "kind": "delete", "schema": "public", "table": "table2_with_pk", "oldkeys": { "keynames": ["a", "c"], "keytypes": ["integer", "timestamp without time zone"], "keyvalues": [1, "2018-03-27 12:05:29.914496"] } } ,{ "kind": "delete", "schema": "public", "table": "table2_with_pk", "oldkeys": { "keynames": ["a", "c"], "keytypes": ["integer", "timestamp without time zone"], "keyvalues": [2, "2018-03-27 12:05:29.914496"] } } ,{ "kind": "insert", "schema": "public", "table": "table2_without_pk", "columnnames": ["a", "b", "c"], "columntypes": ["integer", "numeric(5,2)", "text"], "columnvalues": [1, 2.34, "Tapir"] } ] } stop DROP TABLE DROP TABLEЧÑÐ¾Ð±Ñ ÑдалиÑÑ ÑÐ»Ð¾Ñ Ð² пеÑвом ÑеÑминале:
Ctrl+C $ pg_recvlogical -d postgres --slot test_slot --drop-slot
H.3.3.2. ÐÑзов SQL-ÑÑнкÑий #
Ðиже пÑедÑÑÐ°Ð²Ð»ÐµÐ½Ñ Ð¿ÑимеÑÑ, как полÑÑиÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² wal2json Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ SQL.
ÐÑли Ð´Ð»Ñ format-version задано знаÑение 1, ÑкÑÐ¸Ð¿Ñ Ð¼Ð¾Ð¶ÐµÑ Ð²ÑглÑдеÑÑ Ñак:
$ cat /tmp/example2.sql
CREATE TABLE table2_with_pk (a SERIAL, b VARCHAR(30), c TIMESTAMP NOT NULL, PRIMARY KEY(a, c));
CREATE TABLE table2_without_pk (a SERIAL, b NUMERIC(5,2), c TEXT);
SELECT 'init' FROM pg_create_logical_replication_slot('test_slot', 'wal2json');
BEGIN;
INSERT INTO table2_with_pk (b, c) VALUES('Backup and Restore', now());
INSERT INTO table2_with_pk (b, c) VALUES('Tuning', now());
INSERT INTO table2_with_pk (b, c) VALUES('Replication', now());
SELECT pg_logical_emit_message(true, 'wal2json', 'this message will be delivered');
SELECT pg_logical_emit_message(true, 'pgoutput', 'this message will be filtered');
DELETE FROM table2_with_pk WHERE a < 3;
SELECT pg_logical_emit_message(false, 'wal2json', 'this non-transactional message will be delivered even if you rollback the transaction');
INSERT INTO table2_without_pk (b, c) VALUES(2.34, 'Tapir');
-- ÑÑа запиÑÑ Ð½Ðµ добавлÑеÑÑÑ Ð² поÑок, Ñак как оÑÑÑÑÑÑвÑÐµÑ Ð¿ÐµÑвиÑнÑй клÑÑ Ð¸Ð»Ð¸ ÑепликаÑионнÑй иденÑиÑикаÑоÑ
UPDATE table2_without_pk SET c = 'Anta' WHERE c = 'Tapir';
COMMIT;
SELECT data FROM pg_logical_slot_get_changes('test_slot', NULL, NULL, 'pretty-print', '1', 'add-msg-prefixes', 'wal2json');
SELECT 'stop' FROM pg_drop_replication_slot('test_slot');
DROP TABLE table2_with_pk;
DROP TABLE table2_without_pk;
ÐжидаемÑй вÑвод Ð¼Ð¾Ð¶ÐµÑ Ð²ÑглÑдеÑÑ Ñак:
$ psql -At -f /tmp/example2.sql postgres
CREATE TABLE
CREATE TABLE
init
BEGIN
INSERT 0 1
INSERT 0 1
INSERT 0 1
3/78C2CA50
3/78C2CAA8
DELETE 2
3/78C2CBD8
INSERT 0 1
UPDATE 1
COMMIT
{
"change": [
{
"kind": "message",
"transactional": false,
"prefix": "wal2json",
"content": "this non-transactional message will be delivered even if you rollback the transaction"
}
]
}
psql:/tmp/example2.sql:17: WARNING: table "table2_without_pk" without primary key or replica identity is nothing
{
"change": [
{
"kind": "insert",
"schema": "public",
"table": "table2_with_pk",
"columnnames": ["a", "b", "c"],
"columntypes": ["integer", "character varying(30)", "timestamp without time zone"],
"columnvalues": [1, "Backup and Restore", "2018-03-27 12:05:29.914496"]
}
,{
"kind": "insert",
"schema": "public",
"table": "table2_with_pk",
"columnnames": ["a", "b", "c"],
"columntypes": ["integer", "character varying(30)", "timestamp without time zone"],
"columnvalues": [2, "Tuning", "2018-03-27 12:05:29.914496"]
}
,{
"kind": "insert",
"schema": "public",
"table": "table2_with_pk",
"columnnames": ["a", "b", "c"],
"columntypes": ["integer", "character varying(30)", "timestamp without time zone"],
"columnvalues": [3, "Replication", "2018-03-27 12:05:29.914496"]
}
,{
"kind": "message",
"transactional": true,
"prefix": "wal2json",
"content": "this message will be delivered"
}
,{
"kind": "delete",
"schema": "public",
"table": "table2_with_pk",
"oldkeys": {
"keynames": ["a", "c"],
"keytypes": ["integer", "timestamp without time zone"],
"keyvalues": [1, "2018-03-27 12:05:29.914496"]
}
}
,{
"kind": "delete",
"schema": "public",
"table": "table2_with_pk",
"oldkeys": {
"keynames": ["a", "c"],
"keytypes": ["integer", "timestamp without time zone"],
"keyvalues": [2, "2018-03-27 12:05:29.914496"]
}
}
,{
"kind": "insert",
"schema": "public",
"table": "table2_without_pk",
"columnnames": ["a", "b", "c"],
"columntypes": ["integer", "numeric(5,2)", "text"],
"columnvalues": [1, 2.34, "Tapir"]
}
]
}
stop
DROP TABLE
DROP TABLE
ÐÑли Ð´Ð»Ñ format-version задано знаÑение 2, ÑкÑÐ¸Ð¿Ñ Ð¼Ð¾Ð¶ÐµÑ Ð²ÑглÑдеÑÑ Ñак:
$ cat /tmp/example3.sql
CREATE TABLE table3_with_pk (a SERIAL, b VARCHAR(30), c TIMESTAMP NOT NULL, PRIMARY KEY(a, c));
CREATE TABLE table3_without_pk (a SERIAL, b NUMERIC(5,2), c TEXT);
SELECT 'init' FROM pg_create_logical_replication_slot('test_slot', 'wal2json');
BEGIN;
INSERT INTO table3_with_pk (b, c) VALUES('Backup and Restore', now());
INSERT INTO table3_with_pk (b, c) VALUES('Tuning', now());
INSERT INTO table3_with_pk (b, c) VALUES('Replication', now());
SELECT pg_logical_emit_message(true, 'wal2json', 'this message will be delivered');
SELECT pg_logical_emit_message(true, 'pgoutput', 'this message will be filtered');
DELETE FROM table3_with_pk WHERE a < 3;
SELECT pg_logical_emit_message(false, 'wal2json', 'this non-transactional message will be delivered even if you rollback the transaction');
INSERT INTO table3_without_pk (b, c) VALUES(2.34, 'Tapir');
-- ÑÑа запиÑÑ Ð½Ðµ добавлÑеÑÑÑ Ð² поÑок, Ñак как оÑÑÑÑÑÑвÑÐµÑ Ð¿ÐµÑвиÑнÑй клÑÑ Ð¸Ð»Ð¸ ÑепликаÑионнÑй иденÑиÑикаÑоÑ
UPDATE table3_without_pk SET c = 'Anta' WHERE c = 'Tapir';
COMMIT;
SELECT data FROM pg_logical_slot_get_changes('test_slot', NULL, NULL, 'format-version', '2', 'add-msg-prefixes', 'wal2json');
SELECT 'stop' FROM pg_drop_replication_slot('test_slot');
DROP TABLE table3_with_pk;
DROP TABLE table3_without_pk;
ÐжидаемÑй вÑвод Ð¼Ð¾Ð¶ÐµÑ Ð²ÑглÑдеÑÑ Ñак:
$ psql -At -f /tmp/example3.sql postgres
CREATE TABLE
CREATE TABLE
init
BEGIN
INSERT 0 1
INSERT 0 1
INSERT 0 1
3/78CB8F30
3/78CB8F88
DELETE 2
3/78CB90B8
INSERT 0 1
UPDATE 1
COMMIT
psql:/tmp/example3.sql:20: WARNING: no tuple identifier for UPDATE in table "public"."table3_without_pk"
{"action":"M","transactional":false,"prefix":"wal2json","content":"this non-transactional message will be delivered even if you rollback the transaction"}
{"action":"B"}
{"action":"I","schema":"public","table":"table3_with_pk","columns":[{"name":"a","type":"integer","value":1},{"name":"b","type":"character varying(30)","value":"Backup and Restore"},{"name":"c","type":"timestamp without time zone","value":"2019-12-29 04:58:34.806671"}]}
{"action":"I","schema":"public","table":"table3_with_pk","columns":[{"name":"a","type":"integer","value":2},{"name":"b","type":"character varying(30)","value":"Tuning"},{"name":"c","type":"timestamp without time zone","value":"2019-12-29 04:58:34.806671"}]}
{"action":"I","schema":"public","table":"table3_with_pk","columns":[{"name":"a","type":"integer","value":3},{"name":"b","type":"character varying(30)","value":"Replication"},{"name":"c","type":"timestamp without time zone","value":"2019-12-29 04:58:34.806671"}]}
{"action":"M","transactional":true,"prefix":"wal2json","content":"this message will be delivered"}
{"action":"D","schema":"public","table":"table3_with_pk","identity":[{"name":"a","type":"integer","value":1},{"name":"c","type":"timestamp without time zone","value":"2019-12-29 04:58:34.806671"}]}
{"action":"D","schema":"public","table":"table3_with_pk","identity":[{"name":"a","type":"integer","value":2},{"name":"c","type":"timestamp without time zone","value":"2019-12-29 04:58:34.806671"}]}
{"action":"I","schema":"public","table":"table3_without_pk","columns":[{"name":"a","type":"integer","value":1},{"name":"b","type":"numeric(5,2)","value":2.34},{"name":"c","type":"text","value":"Tapir"}]}
{"action":"C"}
stop
DROP TABLE
DROP TABLE