Skip to content

Commit 4775dec

Browse files
author
Nikita Glukhov
committed
Shared jsonb TOAST
1 parent 30683da commit 4775dec

File tree

9 files changed

+937
-59
lines changed

9 files changed

+937
-59
lines changed

src/backend/access/common/heaptuple.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#include "access/tupdesc_details.h"
6363
#include "executor/tuptable.h"
6464
#include "utils/expandeddatum.h"
65+
#include "utils/jsonb.h" /* FIXME */
6566

6667

6768
/* Does att's datatype allow packing into the 1-byte-header varlena format? */
@@ -269,6 +270,13 @@ fill_val(Form_pg_attribute att,
269270
data_length = VARSIZE(val);
270271
memcpy(data, val, data_length);
271272
}
273+
274+
if (!(*infomask & HEAP_HASEXTERNAL) &&
275+
att->atttypid == JSONBOID) /* FIXME */
276+
{
277+
if (JsonbHasExternal(datum))
278+
*infomask |= HEAP_HASEXTERNAL;
279+
}
272280
}
273281
else if (att->attlen == -2)
274282
{

src/backend/access/heap/heaptoast.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
108108
Datum toast_values[MaxHeapAttributeNumber];
109109
Datum toast_oldvalues[MaxHeapAttributeNumber];
110110
ToastAttrInfo toast_attr[MaxHeapAttributeNumber];
111+
AttrToaster toasters[MaxHeapAttributeNumber];
111112
ToastTupleContext ttc;
112113

113114
/*
@@ -154,6 +155,7 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
154155
ttc.ttc_oldisnull = toast_oldisnull;
155156
}
156157
ttc.ttc_attr = toast_attr;
158+
ttc.ttc_toaster = toasters;
157159
toast_tuple_init(&ttc);
158160

159161
/* ----------
@@ -198,6 +200,7 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
198200
{
199201
ToastAttrInfo *attr = &ttc.ttc_attr[biggest_attno];
200202
Datum *p_value = &ttc.ttc_values[biggest_attno];
203+
AttrToaster toaster = ttc.ttc_toaster[biggest_attno];
201204
Datum old_value = *p_value;
202205
Datum compressed_value = (Datum) 0;
203206
bool externalize = false;
@@ -208,9 +211,7 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
208211

209212
attr->tai_colflags &= ~TOASTCOL_NEEDS_FREE;
210213

211-
/* FIXME pass flag to check compressedSize < maxDataLen */
212-
toast_tuple_try_compression(&ttc, biggest_attno);
213-
214+
/* calculate size of other attributes */
214215
{
215216
struct varlena tmp;
216217

@@ -221,6 +222,26 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
221222
*p_value = old_value;
222223
}
223224

225+
if (toaster != NULL)
226+
{
227+
Datum new_value = toaster(ttc.ttc_rel, *p_value,
228+
(Datum) 0, maxDataLen - size,
229+
attr->tai_compression);
230+
231+
if (new_value != *p_value)
232+
{
233+
*p_value = new_value;
234+
attr->tai_size = VARSIZE(new_value);
235+
attr->tai_colflags = TOASTCOL_NEEDS_FREE;
236+
ttc.ttc_flags |= (TOAST_NEEDS_CHANGE | TOAST_NEEDS_FREE);
237+
continue;
238+
}
239+
}
240+
241+
/* FIXME pass flag to check compressedSize < maxDataLen */
242+
toast_tuple_try_compression(&ttc, biggest_attno);
243+
244+
224245
if (attr->tai_colflags & TOASTCOL_INCOMPRESSIBLE)
225246
{
226247
attr->tai_colflags |= needs_free;

src/backend/access/table/toast_helper.c

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
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

src/backend/utils/adt/json_generic.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ JsonExpand(Json *tmp, Datum value, bool freeValue, JsonContainerOps *ops)
751751

752752
if (tmp)
753753
{
754-
Assert(0);
754+
//Assert(0);
755755
json = tmp;
756756
json->obj.isTemporary = true;
757757
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy