87
87
#include "access/toasterapi.h"
88
88
#include "access/heapam.h"
89
89
#include "access/rewriteheap.h"
90
+ #include "access/toast_helper.h"
90
91
#include "access/transam.h"
91
92
#include "access/xact.h"
92
93
#include "access/xlog_internal.h"
@@ -157,19 +158,6 @@ typedef struct ReorderBufferIterTXNState
157
158
ReorderBufferIterTXNEntry entries [FLEXIBLE_ARRAY_MEMBER ];
158
159
} ReorderBufferIterTXNState ;
159
160
160
- /* toast datastructures */
161
- typedef struct ReorderBufferToastEnt
162
- {
163
- Oid chunk_id ; /* toast_table.chunk_id */
164
- int32 last_chunk_seq ; /* toast_table.chunk_seq of the last chunk we
165
- * have seen */
166
- Size num_chunks ; /* number of chunks we've already seen */
167
- Size size ; /* combined size of chunks seen */
168
- dlist_head chunks ; /* linked list of chunks */
169
- struct varlena * reconstructed ; /* reconstructed varlena now pointed to in
170
- * main tup */
171
- } ReorderBufferToastEnt ;
172
-
173
161
/* Disk serialization support datastructures */
174
162
typedef struct ReorderBufferDiskChange
175
163
{
@@ -4724,15 +4712,16 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
4724
4712
bool * free ;
4725
4713
HeapTuple tmphtup ;
4726
4714
Relation toast_rel ;
4727
- TupleDesc toast_desc ;
4728
4715
MemoryContext oldcontext ;
4729
4716
ReorderBufferTupleBuf * newtup ;
4730
4717
Size old_size ;
4731
4718
4732
4719
/* no toast tuples changed */
4733
- if (txn -> toast_hash == NULL )
4734
- return ;
4735
-
4720
+ if (!change -> data .tp .newtuple ||
4721
+ !HeapTupleHasExternal (& change -> data .tp .newtuple -> tuple ))
4722
+ {
4723
+ return ;
4724
+ }
4736
4725
/*
4737
4726
* We're going to modify the size of the change. So, to make sure the
4738
4727
* accounting is correct we record the current change size and then after
@@ -4757,8 +4746,6 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
4757
4746
elog (ERROR , "could not open toast relation with OID %u (base relation \"%s\")" ,
4758
4747
relation -> rd_rel -> reltoastrelid , RelationGetRelationName (relation ));
4759
4748
4760
- toast_desc = RelationGetDescr (toast_rel );
4761
-
4762
4749
/* should we allocate from stack instead? */
4763
4750
attrs = palloc0 (sizeof (Datum ) * desc -> natts );
4764
4751
isnull = palloc0 (sizeof (bool ) * desc -> natts );
@@ -4771,16 +4758,14 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
4771
4758
for (natt = 0 ; natt < desc -> natts ; natt ++ )
4772
4759
{
4773
4760
Form_pg_attribute attr = TupleDescAttr (desc , natt );
4774
- ReorderBufferToastEnt * ent ;
4761
+ TsrRoutine * toaster ;
4775
4762
struct varlena * varlena ;
4776
4763
4777
4764
/* va_rawsize is the size of the original datum -- including header */
4778
- struct varatt_external toast_pointer ;
4779
4765
struct varatt_indirect redirect_pointer ;
4780
4766
struct varlena * new_datum = NULL ;
4781
4767
struct varlena * reconstructed ;
4782
- dlist_iter it ;
4783
- Size data_done = 0 ;
4768
+ bool need_free ;
4784
4769
4785
4770
/* system columns aren't toasted */
4786
4771
if (attr -> attnum < 0 )
@@ -4801,68 +4786,40 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
4801
4786
varlena = (struct varlena * ) DatumGetPointer (attrs [natt ]);
4802
4787
4803
4788
/* no need to do anything if the tuple isn't external */
4804
- if (!VARATT_IS_EXTERNAL (varlena ))
4805
- continue ;
4806
-
4807
- VARATT_EXTERNAL_GET_POINTER (toast_pointer , varlena );
4808
-
4809
- /*
4810
- * Check whether the toast tuple changed, replace if so.
4811
- */
4812
- ent = (ReorderBufferToastEnt * )
4813
- hash_search (txn -> toast_hash ,
4814
- (void * ) & toast_pointer .va_valueid ,
4815
- HASH_FIND ,
4816
- NULL );
4817
- if (ent == NULL )
4789
+ if (!VARATT_IS_EXTERNAL_ONDISK (varlena ) &&
4790
+ !VARATT_IS_CUSTOM (varlena ))
4818
4791
continue ;
4819
4792
4820
- new_datum =
4821
- (struct varlena * ) palloc0 (INDIRECT_POINTER_SIZE );
4822
-
4823
- free [natt ] = true;
4824
-
4825
- reconstructed = palloc0 (toast_pointer .va_rawsize );
4826
-
4827
- ent -> reconstructed = reconstructed ;
4828
-
4829
- /* stitch toast tuple back together from its parts */
4830
- dlist_foreach (it , & ent -> chunks )
4793
+ toaster = SearchTsrCache (attr -> atttoaster );
4794
+ if (toaster -> reconstruct )
4831
4795
{
4832
- bool isnull ;
4833
- ReorderBufferChange * cchange ;
4834
- ReorderBufferTupleBuf * ctup ;
4835
- Pointer chunk ;
4836
-
4837
- cchange = dlist_container (ReorderBufferChange , node , it .cur );
4838
- ctup = cchange -> data .tp .newtuple ;
4839
- chunk = DatumGetPointer (fastgetattr (& ctup -> tuple , 3 , toast_desc , & isnull ));
4840
-
4841
- Assert (!isnull );
4842
- Assert (!VARATT_IS_EXTERNAL (chunk ));
4843
- Assert (!VARATT_IS_SHORT (chunk ));
4844
-
4845
- memcpy (VARDATA (reconstructed ) + data_done ,
4846
- VARDATA (chunk ),
4847
- VARSIZE (chunk ) - VARHDRSZ );
4848
- data_done += VARSIZE (chunk ) - VARHDRSZ ;
4796
+ reconstructed = (struct varlena * ) DatumGetPointer (
4797
+ toaster -> reconstruct (toast_rel , varlena , txn -> toast_hash , & need_free ));
4849
4798
}
4850
- Assert (data_done == VARATT_EXTERNAL_GET_EXTSIZE (toast_pointer ));
4851
-
4852
- /* make sure its marked as compressed or not */
4853
- if (VARATT_EXTERNAL_IS_COMPRESSED (toast_pointer ))
4854
- SET_VARSIZE_COMPRESSED (reconstructed , data_done + VARHDRSZ );
4855
4799
else
4856
- SET_VARSIZE (reconstructed , data_done + VARHDRSZ );
4800
+ {
4801
+ ereport (ERROR ,
4802
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
4803
+ errmsg ("TOASTER does not support reconstruction of values" )));
4804
+ }
4805
+
4806
+ if (!reconstructed )
4807
+ continue ;
4808
+
4809
+ if (need_free )
4810
+ txn -> toast_reconstructed = lappend (txn -> toast_reconstructed , reconstructed );
4857
4811
4858
4812
memset (& redirect_pointer , 0 , sizeof (redirect_pointer ));
4859
4813
redirect_pointer .pointer = reconstructed ;
4860
4814
4815
+ new_datum = (struct varlena * ) palloc0 (INDIRECT_POINTER_SIZE );
4816
+
4861
4817
SET_VARTAG_EXTERNAL (new_datum , VARTAG_INDIRECT );
4862
4818
memcpy (VARDATA_EXTERNAL (new_datum ), & redirect_pointer ,
4863
4819
sizeof (redirect_pointer ));
4864
4820
4865
4821
attrs [natt ] = PointerGetDatum (new_datum );
4822
+ free [natt ] = true;
4866
4823
}
4867
4824
4868
4825
/*
@@ -4910,6 +4867,9 @@ ReorderBufferToastReset(ReorderBuffer *rb, ReorderBufferTXN *txn)
4910
4867
HASH_SEQ_STATUS hstat ;
4911
4868
ReorderBufferToastEnt * ent ;
4912
4869
4870
+ list_free_deep (txn -> toast_reconstructed );
4871
+ txn -> toast_reconstructed = NIL ;
4872
+
4913
4873
if (txn -> toast_hash == NULL )
4914
4874
return ;
4915
4875
0 commit comments