2020#include "access/toast_internals.h"
2121#include "catalog/pg_type_d.h"
2222
23+ /* FIXME */ extern Datum jsonb_toaster (Relation rel , Datum new_val ,
24+ Datum old_val , int max_size , char cmethod );
2325
2426/*
2527 * Prepare to TOAST a tuple.
@@ -55,6 +57,7 @@ toast_tuple_init(ToastTupleContext *ttc)
5557 ttc -> ttc_attr [i ].tai_colflags = 0 ;
5658 ttc -> ttc_attr [i ].tai_oldexternal = NULL ;
5759 ttc -> ttc_attr [i ].tai_compression = att -> attcompression ;
60+ ttc -> ttc_toaster [i ] = att -> atttypid == JSONBOID ? jsonb_toaster : NULL ;
5861
5962 if (ttc -> ttc_oldvalues != NULL )
6063 {
@@ -70,30 +73,79 @@ toast_tuple_init(ToastTupleContext *ttc)
7073 * If the old value is stored on disk, check if it has changed so
7174 * we have to delete it later.
7275 */
73- if (att -> attlen == -1 && !ttc -> ttc_oldisnull [i ] &&
74- VARATT_IS_EXTERNAL_ONDISK (old_value ))
76+ if (att -> attlen == -1 && !ttc -> ttc_oldisnull [i ])
7577 {
76- if (ttc -> ttc_isnull [i ] ||
77- !VARATT_IS_EXTERNAL_ONDISK (new_value ) ||
78- memcmp ((char * ) old_value , (char * ) new_value ,
79- VARSIZE_EXTERNAL (old_value )) != 0 )
78+ if (VARATT_IS_EXTERNAL_ONDISK (old_value ) ||
79+ VARATT_IS_EXTERNAL_ONDISK_INLINE (old_value ))
8080 {
81- /*
82- * The old external stored value isn't needed any more
83- * after the update
84- */
85- ttc -> ttc_attr [i ].tai_colflags |= TOASTCOL_NEEDS_DELETE_OLD ;
81+ if (ttc -> ttc_isnull [i ] ||
82+ (!VARATT_IS_EXTERNAL_ONDISK (new_value ) &&
83+ !VARATT_IS_EXTERNAL_ONDISK_INLINE (new_value )))
84+ {
85+ /*
86+ * The old external stored value isn't needed
87+ * any more after the update
88+ */
89+ ttc -> ttc_attr [i ].tai_colflags |= TOASTCOL_NEEDS_DELETE_OLD ;
90+ ttc -> ttc_flags |= TOAST_NEEDS_DELETE_OLD ;
91+ }
92+ else
93+ {
94+ struct varatt_external old_toast_ptr ;
95+ struct varatt_external new_toast_ptr ;
96+
97+ VARATT_EXTERNAL_INLINE_GET_POINTER (old_toast_ptr , old_value );
98+ VARATT_EXTERNAL_INLINE_GET_POINTER (new_toast_ptr , new_value );
99+
100+ if (memcmp (& old_toast_ptr , & new_toast_ptr ,
101+ sizeof (old_toast_ptr )) != 0 )
102+ {
103+ /*
104+ * The old external stored value isn't
105+ * needed any more after the update
106+ */
107+ ttc -> ttc_attr [i ].tai_colflags |= TOASTCOL_NEEDS_DELETE_OLD ;
108+ ttc -> ttc_flags |= TOAST_NEEDS_DELETE_OLD ;
109+ }
110+ else
111+ {
112+ /*
113+ * This attribute isn't changed by this
114+ * update so we reuse the original reference
115+ * to the old value in the new tuple.
116+ */
117+ ttc -> ttc_attr [i ].tai_colflags |= TOASTCOL_IGNORE ;
118+ continue ;
119+ }
120+ }
121+ }
122+ else if (ttc -> ttc_toaster [i ] &&
123+ (ttc -> ttc_isnull [i ] ||
124+ VARATT_IS_EXTERNAL_ONDISK (new_value ) ||
125+ memcmp ((char * ) old_value , (char * ) new_value ,
126+ VARSIZE_ANY (old_value )) != 0 ))
127+ {
128+ ttc -> ttc_attr [i ].tai_colflags |= TOASTCOL_NEEDS_COMPARE_OLD ;
86129 ttc -> ttc_flags |= TOAST_NEEDS_DELETE_OLD ;
87130 }
88- else
131+ }
132+
133+ if (ttc -> ttc_toaster [i ] &&
134+ (ttc -> ttc_attr [i ].tai_colflags & (TOASTCOL_NEEDS_DELETE_OLD |
135+ TOASTCOL_NEEDS_COMPARE_OLD )) != 0 )
136+ {
137+ Datum new_val =
138+ ttc -> ttc_toaster [i ](ttc -> ttc_rel ,
139+ ttc -> ttc_isnull [i ] ? (Datum ) 0 : ttc -> ttc_values [i ],
140+ ttc -> ttc_oldvalues [i ], -1 );
141+
142+ if (new_val != (Datum ) 0 )
89143 {
90- /*
91- * This attribute isn't changed by this update so we reuse
92- * the original reference to the old value in the new
93- * tuple.
94- */
95- ttc -> ttc_attr [i ].tai_colflags |= TOASTCOL_IGNORE ;
96- continue ;
144+ if (ttc -> ttc_attr [i ].tai_colflags & TOASTCOL_NEEDS_FREE )
145+ pfree (DatumGetPointer (ttc -> ttc_values [i ]));
146+
147+ ttc -> ttc_attr [i ].tai_colflags |= TOASTCOL_NEEDS_FREE ;
148+ ttc -> ttc_values [i ] = new_val ;
97149 }
98150 }
99151 }
@@ -102,6 +154,22 @@ toast_tuple_init(ToastTupleContext *ttc)
102154 /*
103155 * For INSERT simply get the new value
104156 */
157+
158+ if (ttc -> ttc_toaster [i ] && !ttc -> ttc_isnull [i ])
159+ {
160+ Datum new_val =
161+ ttc -> ttc_toaster [i ](ttc -> ttc_rel , ttc -> ttc_values [i ], (Datum ) 0 , -1 );
162+
163+ if (new_val != (Datum ) 0 )
164+ {
165+ if (ttc -> ttc_attr [i ].tai_colflags & TOASTCOL_NEEDS_FREE )
166+ pfree (DatumGetPointer (ttc -> ttc_values [i ]));
167+
168+ ttc -> ttc_attr [i ].tai_colflags |= TOASTCOL_NEEDS_FREE ;
169+ ttc -> ttc_values [i ] = new_val ;
170+ }
171+ }
172+
105173 new_value = (struct varlena * ) DatumGetPointer (ttc -> ttc_values [i ]);
106174 }
107175
0 commit comments