20
20
#include "access/toast_internals.h"
21
21
#include "catalog/pg_type_d.h"
22
22
23
+ /* FIXME */ extern Datum jsonb_toaster (Relation rel , Datum new_val ,
24
+ Datum old_val , int max_size , char cmethod );
23
25
24
26
/*
25
27
* Prepare to TOAST a tuple.
@@ -55,6 +57,7 @@ toast_tuple_init(ToastTupleContext *ttc)
55
57
ttc -> ttc_attr [i ].tai_colflags = 0 ;
56
58
ttc -> ttc_attr [i ].tai_oldexternal = NULL ;
57
59
ttc -> ttc_attr [i ].tai_compression = att -> attcompression ;
60
+ ttc -> ttc_toaster [i ] = att -> atttypid == JSONBOID ? jsonb_toaster : NULL ;
58
61
59
62
if (ttc -> ttc_oldvalues != NULL )
60
63
{
@@ -70,30 +73,79 @@ toast_tuple_init(ToastTupleContext *ttc)
70
73
* If the old value is stored on disk, check if it has changed so
71
74
* we have to delete it later.
72
75
*/
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 ])
75
77
{
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 ))
80
80
{
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 ;
86
129
ttc -> ttc_flags |= TOAST_NEEDS_DELETE_OLD ;
87
130
}
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 )
89
143
{
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 ;
97
149
}
98
150
}
99
151
}
@@ -102,6 +154,22 @@ toast_tuple_init(ToastTupleContext *ttc)
102
154
/*
103
155
* For INSERT simply get the new value
104
156
*/
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
+
105
173
new_value = (struct varlena * ) DatumGetPointer (ttc -> ttc_values [i ]);
106
174
}
107
175
0 commit comments