Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5e01001

Browse files
author
Amit Kapila
committed
WAL log unchanged toasted replica identity key attributes.
Currently, during UPDATE, the unchanged replica identity key attributesare not logged separately because they are getting logged as part of thenew tuple. But if they are stored externally then the untoasted values arenot getting logged as part of the new tuple and logical replication won'tbe able to replicate such UPDATEs. So we need to log such attributes aspart of the old_key_tuple during UPDATE.Reported-by: Haiying TangAuthor: Dilip Kumar and Amit KapilaReviewed-by: Alvaro Herrera, Haiying Tang, Andres FreundBackpatch-through: 10Discussion:https://postgr.es/m/OS0PR01MB611342D0A92D4F4BF26C0F47FB229@OS0PR01MB6113.jpnprd01.prod.outlook.com
1 parent0052fb4 commit5e01001

File tree

3 files changed

+123
-69
lines changed

3 files changed

+123
-69
lines changed

‎contrib/test_decoding/expected/toast.out‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ SELECT substr(data, 1, 200) FROM pg_logical_slot_get_changes('regression_slot',
7777
table public.toasted_key: INSERT: id[integer]:1 toasted_key[text]:'1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123
7878
COMMIT
7979
BEGIN
80-
table public.toasted_key: UPDATE:id[integer]:1 toasted_key[text]:unchanged-toast-datum toasted_col1[text]:unchanged-toast-datum toasted_col2[text]:'987654321098765432109876543210987654321098765432109
80+
table public.toasted_key: UPDATE:old-key: toasted_key[text]:'123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
8181
COMMIT
8282
BEGIN
8383
table public.toasted_key: UPDATE: old-key: toasted_key[text]:'123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678

‎doc/src/sgml/ref/alter_table.sgml‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -871,10 +871,11 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
871871
<listitem>
872872
<para>
873873
This form changes the information which is written to the write-ahead log
874-
to identify rows which are updated or deleted. This option has no effect
875-
except when logical replication is in use.
876-
In all cases, no old values are logged unless at least one of the columns
877-
that would be logged differs between the old and new versions of the row.
874+
to identify rows which are updated or deleted.
875+
In most cases, the old value of each column is only logged if it differs
876+
from the new value; however, if the old value is stored externally, it is
877+
always logged regardless of whether it changed.
878+
This option has no effect except when logical replication is in use.
878879
<variablelist>
879880
<varlistentry>
880881
<term><literal>DEFAULT</literal></term>

‎src/backend/access/heap/heapam.c‎

Lines changed: 117 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,11 @@ static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf,
7878
Buffernewbuf,HeapTupleoldtup,
7979
HeapTuplenewtup,HeapTupleold_key_tuple,
8080
boolall_visible_cleared,boolnew_all_visible_cleared);
81-
staticBitmapset*HeapDetermineModifiedColumns(Relationrelation,
82-
Bitmapset*interesting_cols,
83-
HeapTupleoldtup,HeapTuplenewtup);
81+
staticBitmapset*HeapDetermineColumnsInfo(Relationrelation,
82+
Bitmapset*interesting_cols,
83+
Bitmapset*external_cols,
84+
HeapTupleoldtup,HeapTuplenewtup,
85+
bool*has_external);
8486
staticboolheap_acquire_tuplock(Relationrelation,ItemPointertid,
8587
LockTupleModemode,LockWaitPolicywait_policy,
8688
bool*have_tuple_lock);
@@ -106,7 +108,7 @@ static bool ConditionalMultiXactIdWait(MultiXactId multi, MultiXactStatus status
106108
staticvoidindex_delete_sort(TM_IndexDeleteOp*delstate);
107109
staticintbottomup_sort_and_shrink(TM_IndexDeleteOp*delstate);
108110
staticXLogRecPtrlog_heap_new_cid(Relationrelation,HeapTupletup);
109-
staticHeapTupleExtractReplicaIdentity(Relationrel,HeapTupletup,boolkey_changed,
111+
staticHeapTupleExtractReplicaIdentity(Relationrel,HeapTupletup,boolkey_required,
110112
bool*copy);
111113

112114

@@ -3184,6 +3186,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
31843186
boolall_visible_cleared_new= false;
31853187
boolchecked_lockers;
31863188
boollocker_remains;
3189+
boolid_has_external= false;
31873190
TransactionIdxmax_new_tuple,
31883191
xmax_old_tuple;
31893192
uint16infomask_old_tuple,
@@ -3251,7 +3254,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
32513254
Assert(ItemIdIsNormal(lp));
32523255

32533256
/*
3254-
* Fill in enough data in oldtup forHeapDetermineModifiedColumns to work
3257+
* Fill in enough data in oldtup forHeapDetermineColumnsInfo to work
32553258
* properly.
32563259
*/
32573260
oldtup.t_tableOid=RelationGetRelid(relation);
@@ -3262,9 +3265,17 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
32623265
/* the new tuple is ready, except for this: */
32633266
newtup->t_tableOid=RelationGetRelid(relation);
32643267

3265-
/* Determine columns modified by the update. */
3266-
modified_attrs=HeapDetermineModifiedColumns(relation,interesting_attrs,
3267-
&oldtup,newtup);
3268+
/*
3269+
* Determine columns modified by the update. Additionally, identify
3270+
* whether any of the unmodified replica identity key attributes in the
3271+
* old tuple is externally stored or not. This is required because for
3272+
* such attributes the flattened value won't be WAL logged as part of the
3273+
* new tuple so we must include it as part of the old_key_tuple. See
3274+
* ExtractReplicaIdentity.
3275+
*/
3276+
modified_attrs=HeapDetermineColumnsInfo(relation,interesting_attrs,
3277+
id_attrs,&oldtup,
3278+
newtup,&id_has_external);
32683279

32693280
/*
32703281
* If we're not updating any "key" column, we can grab a weaker lock type.
@@ -3864,10 +3875,12 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
38643875
* Compute replica identity tuple before entering the critical section so
38653876
* we don't PANIC upon a memory allocation failure.
38663877
* ExtractReplicaIdentity() will return NULL if nothing needs to be
3867-
* logged.
3878+
* logged. Pass old key required as true only if the replica identity key
3879+
* columns are modified or it has external data.
38683880
*/
38693881
old_key_tuple=ExtractReplicaIdentity(relation,&oldtup,
3870-
bms_overlap(modified_attrs,id_attrs),
3882+
bms_overlap(modified_attrs,id_attrs)||
3883+
id_has_external,
38713884
&old_key_copied);
38723885

38733886
/* NO EREPORT(ERROR) from here till changes are logged */
@@ -4023,47 +4036,15 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
40234036
}
40244037

40254038
/*
4026-
* Check if the specified attribute'svalue issame in both given tuples.
4027-
*Subroutine for HeapDetermineModifiedColumns.
4039+
* Check if the specified attribute'svalues are thesame. Subroutine for
4040+
*HeapDetermineColumnsInfo.
40284041
*/
40294042
staticbool
4030-
heap_tuple_attr_equals(TupleDesctupdesc,intattrnum,
4031-
HeapTupletup1,HeapTupletup2)
4043+
heap_attr_equals(TupleDesctupdesc,intattrnum,Datumvalue1,Datumvalue2,
4044+
boolisnull1,boolisnull2)
40324045
{
4033-
Datumvalue1,
4034-
value2;
4035-
boolisnull1,
4036-
isnull2;
40374046
Form_pg_attributeatt;
40384047

4039-
/*
4040-
* If it's a whole-tuple reference, say "not equal". It's not really
4041-
* worth supporting this case, since it could only succeed after a no-op
4042-
* update, which is hardly a case worth optimizing for.
4043-
*/
4044-
if (attrnum==0)
4045-
return false;
4046-
4047-
/*
4048-
* Likewise, automatically say "not equal" for any system attribute other
4049-
* than tableOID; we cannot expect these to be consistent in a HOT chain,
4050-
* or even to be set correctly yet in the new tuple.
4051-
*/
4052-
if (attrnum<0)
4053-
{
4054-
if (attrnum!=TableOidAttributeNumber)
4055-
return false;
4056-
}
4057-
4058-
/*
4059-
* Extract the corresponding values. XXX this is pretty inefficient if
4060-
* there are many indexed columns. Should HeapDetermineModifiedColumns do
4061-
* a single heap_deform_tuple call on each tuple, instead?But that
4062-
* doesn't work for system columns ...
4063-
*/
4064-
value1=heap_getattr(tup1,attrnum,tupdesc,&isnull1);
4065-
value2=heap_getattr(tup2,attrnum,tupdesc,&isnull2);
4066-
40674048
/*
40684049
* If one value is NULL and other is not, then they are certainly not
40694050
* equal
@@ -4105,24 +4086,96 @@ heap_tuple_attr_equals(TupleDesc tupdesc, int attrnum,
41054086
* Given an updated tuple, determine (and return into the output bitmapset),
41064087
* from those listed as interesting, the set of columns that changed.
41074088
*
4108-
* The input bitmapset is destructively modified; that is OK since this is
4109-
* invoked at most once in heap_update.
4089+
* has_external indicates if any of the unmodified attributes (from those
4090+
* listed as interesting) of the old tuple is a member of external_cols and is
4091+
* stored externally.
4092+
*
4093+
* The input interesting_cols bitmapset is destructively modified; that is OK
4094+
* since this is invoked at most once in heap_update.
41104095
*/
41114096
staticBitmapset*
4112-
HeapDetermineModifiedColumns(Relationrelation,Bitmapset*interesting_cols,
4113-
HeapTupleoldtup,HeapTuplenewtup)
4097+
HeapDetermineColumnsInfo(Relationrelation,
4098+
Bitmapset*interesting_cols,
4099+
Bitmapset*external_cols,
4100+
HeapTupleoldtup,HeapTuplenewtup,
4101+
bool*has_external)
41144102
{
4115-
intattnum;
4103+
intattrnum;
41164104
Bitmapset*modified=NULL;
4105+
TupleDesctupdesc=RelationGetDescr(relation);
41174106

4118-
while ((attnum=bms_first_member(interesting_cols)) >=0)
4107+
while ((attrnum=bms_first_member(interesting_cols)) >=0)
41194108
{
4120-
attnum+=FirstLowInvalidHeapAttributeNumber;
4109+
Datumvalue1,
4110+
value2;
4111+
boolisnull1,
4112+
isnull2;
4113+
4114+
attrnum+=FirstLowInvalidHeapAttributeNumber;
41214115

4122-
if (!heap_tuple_attr_equals(RelationGetDescr(relation),
4123-
attnum,oldtup,newtup))
4116+
/*
4117+
* If it's a whole-tuple reference, say "not equal". It's not really
4118+
* worth supporting this case, since it could only succeed after a
4119+
* no-op update, which is hardly a case worth optimizing for.
4120+
*/
4121+
if (attrnum==0)
4122+
{
41244123
modified=bms_add_member(modified,
4125-
attnum-FirstLowInvalidHeapAttributeNumber);
4124+
attrnum-
4125+
FirstLowInvalidHeapAttributeNumber);
4126+
continue;
4127+
}
4128+
4129+
/*
4130+
* Likewise, automatically say "not equal" for any system attribute
4131+
* other than tableOID; we cannot expect these to be consistent in a
4132+
* HOT chain, or even to be set correctly yet in the new tuple.
4133+
*/
4134+
if (attrnum<0)
4135+
{
4136+
if (attrnum!=TableOidAttributeNumber)
4137+
{
4138+
modified=bms_add_member(modified,
4139+
attrnum-
4140+
FirstLowInvalidHeapAttributeNumber);
4141+
continue;
4142+
}
4143+
}
4144+
4145+
/*
4146+
* Extract the corresponding values. XXX this is pretty inefficient
4147+
* if there are many indexed columns. Should we do a single
4148+
* heap_deform_tuple call on each tuple, instead?But that doesn't
4149+
* work for system columns ...
4150+
*/
4151+
value1=heap_getattr(oldtup,attrnum,tupdesc,&isnull1);
4152+
value2=heap_getattr(newtup,attrnum,tupdesc,&isnull2);
4153+
4154+
if (!heap_attr_equals(tupdesc,attrnum,value1,
4155+
value2,isnull1,isnull2))
4156+
{
4157+
modified=bms_add_member(modified,
4158+
attrnum-
4159+
FirstLowInvalidHeapAttributeNumber);
4160+
continue;
4161+
}
4162+
4163+
/*
4164+
* No need to check attributes that can't be stored externally. Note
4165+
* that system attributes can't be stored externally.
4166+
*/
4167+
if (attrnum<0||isnull1||
4168+
TupleDescAttr(tupdesc,attrnum-1)->attlen!=-1)
4169+
continue;
4170+
4171+
/*
4172+
* Check if the old tuple's attribute is stored externally and is a
4173+
* member of external_cols.
4174+
*/
4175+
if (VARATT_IS_EXTERNAL((structvarlena*)DatumGetPointer(value1))&&
4176+
bms_is_member(attrnum-FirstLowInvalidHeapAttributeNumber,
4177+
external_cols))
4178+
*has_external= true;
41264179
}
41274180

41284181
returnmodified;
@@ -8359,14 +8412,14 @@ log_heap_new_cid(Relation relation, HeapTuple tup)
83598412
* Returns NULL if there's no need to log an identity or if there's no suitable
83608413
* key defined.
83618414
*
8362-
*key_changed should be falseifcaller knows that no replica identity
8363-
*columns changed value. It's always true in the DELETE case.
8415+
*Pass key_required trueifany replica identity columns changed value, or if
8416+
*any of them have any external data. Delete must always pass true.
83648417
*
83658418
* *copy is set to true if the returned tuple is a modified copy rather than
83668419
* the same tuple that was passed in.
83678420
*/
83688421
staticHeapTuple
8369-
ExtractReplicaIdentity(Relationrelation,HeapTupletp,boolkey_changed,
8422+
ExtractReplicaIdentity(Relationrelation,HeapTupletp,boolkey_required,
83708423
bool*copy)
83718424
{
83728425
TupleDescdesc=RelationGetDescr(relation);
@@ -8398,19 +8451,19 @@ ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_changed,
83988451
returntp;
83998452
}
84008453

8401-
/* if the keyhasn'tchanged and we're only logging the key, we're done */
8402-
if (!key_changed)
8454+
/* if the keyisn'trequired and we're only logging the key, we're done */
8455+
if (!key_required)
84038456
returnNULL;
84048457

84058458
/* find out the replica identity columns */
84068459
idattrs=RelationGetIndexAttrBitmap(relation,
84078460
INDEX_ATTR_BITMAP_IDENTITY_KEY);
84088461

84098462
/*
8410-
* If there's no defined replica identity columns, treat as !key_changed.
8463+
* If there's no defined replica identity columns, treat as !key_required.
84118464
* (This case should not be reachable from heap_update, since that should
8412-
* calculatekey_changed accurately. But heap_delete just passes constant
8413-
* true forkey_changed, so we can hit this case in deletes.)
8465+
* calculatekey_required accurately. But heap_delete just passes
8466+
*constanttrue forkey_required, so we can hit this case in deletes.)
84148467
*/
84158468
if (bms_is_empty(idattrs))
84168469
returnNULL;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp