@@ -66,6 +66,27 @@ typedef struct CompressedJsonb
66
66
int offset ;
67
67
} CompressedJsonb ;
68
68
69
+ typedef struct JsonbKVMap
70
+ {
71
+ union
72
+ {
73
+ const uint8 * entries1 ;
74
+ const uint16 * entries2 ;
75
+ const int32 * entries4 ;
76
+ const void * entries ;
77
+ } map ;
78
+ int entry_size ;
79
+ } JsonbKVMap ;
80
+
81
+ #define JSONB_KVMAP_ENTRY_SIZE (nPairs ) \
82
+ ((nPairs) < 256 ? 1 : (nPairs) < 65536 ? 2 : 4)
83
+
84
+ #define JSONB_KVMAP_ENTRY (kvmap , index ) \
85
+ (!(kvmap)->entry_size ? (index) : \
86
+ (kvmap)->entry_size == 1 ? (int32) (kvmap)->map.entries1[index] : \
87
+ (kvmap)->entry_size == 2 ? (int32) (kvmap)->map.entries2[index] : \
88
+ (kvmap)->map.entries4[index])
89
+
69
90
struct JsonbIterator
70
91
{
71
92
JsonIterator ji ;
@@ -81,7 +102,7 @@ struct JsonbIterator
81
102
const JEntry * children ; /* JEntrys for child nodes */
82
103
/* Data proper. This points to the beginning of the variable-length data */
83
104
char * dataProper ;
84
- uint32 * kvMap ;
105
+ JsonbKVMap kvmap ;
85
106
86
107
/* Current item in buffer (up to nElems) */
87
108
int curIndex ;
@@ -550,6 +571,24 @@ JsonFindValueInContainer(JsonContainer *json, uint32 flags, JsonValue *key)
550
571
return NULL ;
551
572
}
552
573
574
+ static void *
575
+ initKVMap (JsonbKVMap * kvmap , void * pentries , int field_count , bool sorted )
576
+ {
577
+ if (sorted )
578
+ {
579
+ kvmap -> map .entries = pentries ;
580
+ kvmap -> entry_size = JSONB_KVMAP_ENTRY_SIZE (field_count );
581
+
582
+ return (char * ) pentries + INTALIGN (field_count * kvmap -> entry_size );
583
+ }
584
+ else
585
+ {
586
+ kvmap -> entry_size = 0 ;
587
+
588
+ return pentries ;
589
+ }
590
+ }
591
+
553
592
/*
554
593
* Find value by key in Jsonb object and fetch it into 'res', which is also
555
594
* returned.
@@ -563,9 +602,9 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
563
602
const JsonbContainer * container = JsonContainerDataPtr (jsc );
564
603
const JEntry * children = container -> children ;
565
604
int count = JsonContainerSize (jsc );
566
- char * baseAddr ;
605
+ char * baseAddr = ( char * ) ( children + count * 2 ) ;
567
606
bool sorted_values = (container -> header & JB_TMASK ) == JB_TOBJECT_SORTED ;
568
- const uint32 * kvmap ;
607
+ JsonbKVMap kvmap ;
569
608
uint32 stopLow ,
570
609
stopHigh ;
571
610
@@ -579,16 +618,8 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
579
618
* Binary search the container. Since we know this is an object, account
580
619
* for *Pairs* of Jentrys
581
620
*/
582
- if (sorted_values )
583
- {
584
- kvmap = & children [count * 2 ];
585
- baseAddr = (char * ) & kvmap [count ];
586
- }
587
- else
588
- {
589
- kvmap = NULL ;
590
- baseAddr = (char * ) (children + count * 2 );
591
- }
621
+ baseAddr = initKVMap (& kvmap , baseAddr , count , sorted_values );
622
+
592
623
stopLow = 0 ;
593
624
stopHigh = count ;
594
625
while (stopLow < stopHigh )
@@ -609,7 +640,7 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
609
640
if (difference == 0 )
610
641
{
611
642
/* Found our key, return corresponding value */
612
- int index = ( sorted_values ? kvmap [ stopMiddle ] : stopMiddle ) + count ;
643
+ int index = JSONB_KVMAP_ENTRY ( & kvmap , stopMiddle ) + count ;
613
644
614
645
if (!res )
615
646
res = palloc (sizeof (JsonbValue ));
@@ -1034,6 +1065,7 @@ JsonbIteratorToken
1034
1065
JsonbIteratorNext (JsonIterator * * jsit , JsonbValue * val , bool skipNested )
1035
1066
{
1036
1067
JsonbIterator * * it = (JsonbIterator * * ) jsit ;
1068
+ int entry_index ;
1037
1069
1038
1070
if (* it == NULL )
1039
1071
return WJB_DONE ;
@@ -1146,17 +1178,19 @@ JsonbIteratorNext(JsonIterator **jsit, JsonbValue *val, bool skipNested)
1146
1178
/* Set state for next call */
1147
1179
(* it )-> state = JBI_OBJECT_KEY ;
1148
1180
1181
+ entry_index = JSONB_KVMAP_ENTRY (& (* it )-> kvmap , (* it )-> curIndex ) + (* it )-> nElems ;
1182
+
1149
1183
fillCompressedJsonbValue ((* it )-> compressed , (* it )-> container ,
1150
- (( * it ) -> kvMap ? ( * it ) -> kvMap [( * it ) -> curIndex ] : ( * it ) -> curIndex ) + ( * it ) -> nElems ,
1184
+ entry_index ,
1151
1185
(* it )-> dataProper ,
1152
- (* it )-> kvMap ?
1153
- getJsonbOffset ((* it )-> container , ( * it ) -> kvMap [( * it ) -> curIndex ] + ( * it ) -> nElems ) :
1186
+ (* it )-> kvmap . entry_size ?
1187
+ getJsonbOffset ((* it )-> container , entry_index ) :
1154
1188
(* it )-> curValueOffset ,
1155
1189
val );
1156
1190
1157
1191
JBE_ADVANCE_OFFSET ((* it )-> curDataOffset ,
1158
1192
(* it )-> children [(* it )-> curIndex ]);
1159
- if (!(* it )-> kvMap )
1193
+ if (!(* it )-> kvmap . entry_size )
1160
1194
JBE_ADVANCE_OFFSET ((* it )-> curValueOffset ,
1161
1195
(* it )-> children [(* it )-> curIndex + (* it )-> nElems ]);
1162
1196
(* it )-> curIndex ++ ;
@@ -1198,6 +1232,7 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
1198
1232
struct CompressedJsonb * cjb )
1199
1233
{
1200
1234
JsonbIterator * it ;
1235
+ int type = container -> header & JB_TMASK ;
1201
1236
1202
1237
it = palloc0 (sizeof (JsonbIterator ));
1203
1238
it -> ji .container = cont ;
@@ -1210,7 +1245,7 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
1210
1245
/* Array starts just after header */
1211
1246
it -> children = container -> children ;
1212
1247
1213
- switch (container -> header & JB_TMASK )
1248
+ switch (type )
1214
1249
{
1215
1250
case JB_TSCALAR :
1216
1251
it -> isScalar = true;
@@ -1225,16 +1260,12 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
1225
1260
break ;
1226
1261
1227
1262
case JB_TOBJECT :
1228
- it -> kvMap = NULL ;
1263
+ case JB_TOBJECT_SORTED :
1229
1264
it -> dataProper =
1230
1265
(char * ) it -> children + it -> nElems * sizeof (JEntry ) * 2 ;
1231
- it -> state = JBI_OBJECT_START ;
1232
- break ;
1266
+ it -> dataProper = initKVMap ( & it -> kvmap , it -> dataProper , it -> nElems ,
1267
+ type == JB_TOBJECT_SORTED ) ;
1233
1268
1234
- case JB_TOBJECT_SORTED :
1235
- it -> kvMap = (uint32 * )
1236
- ((char * ) it -> children + it -> nElems * sizeof (JEntry ) * 2 );
1237
- it -> dataProper = (char * ) & it -> kvMap [it -> nElems ];
1238
1269
it -> state = JBI_OBJECT_START ;
1239
1270
break ;
1240
1271
@@ -1958,6 +1989,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
1958
1989
uint32 header ;
1959
1990
int nPairs = val -> val .object .nPairs ;
1960
1991
int reserved_size ;
1992
+ int kvmap_entry_size ;
1961
1993
bool sorted_values = jsonb_sort_field_values && nPairs > 1 ;
1962
1994
struct
1963
1995
{
@@ -1984,6 +2016,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
1984
2016
{
1985
2017
if (values [i ].index != i )
1986
2018
{
2019
+ kvmap_entry_size = JSONB_KVMAP_ENTRY_SIZE (nPairs );
1987
2020
sorted_values = true;
1988
2021
break ;
1989
2022
}
@@ -2006,16 +2039,45 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
2006
2039
/* Reserve space for the JEntries of the keys and values. */
2007
2040
reserved_size = sizeof (JEntry ) * nPairs * 2 ;
2008
2041
if (sorted_values )
2009
- reserved_size += sizeof ( int32 ) * nPairs ;
2042
+ reserved_size += INTALIGN ( kvmap_entry_size * nPairs ) ;
2010
2043
2011
2044
jentry_offset = reserveFromBuffer (buffer , reserved_size );
2012
2045
2013
2046
/* Write key-value map */
2014
2047
if (sorted_values )
2015
2048
{
2049
+ int kvmap_offset = jentry_offset + sizeof (JEntry ) * nPairs * 2 ;
2050
+
2016
2051
for (i = 0 ; i < nPairs ; i ++ )
2017
- copyToBuffer (buffer , jentry_offset + sizeof (JEntry ) * nPairs * 2 + values [i ].index * sizeof (int32 ),
2018
- & i , sizeof (int32 ));
2052
+ {
2053
+ uint8 entry1 ;
2054
+ uint16 entry2 ;
2055
+ uint32 entry4 ;
2056
+ void * pentry ;
2057
+
2058
+ if (kvmap_entry_size == 1 )
2059
+ {
2060
+ entry1 = (uint8 ) i ;
2061
+ pentry = & entry1 ;
2062
+ }
2063
+ else if (kvmap_entry_size == 2 )
2064
+ {
2065
+ entry2 = (uint16 ) i ;
2066
+ pentry = & entry2 ;
2067
+ }
2068
+ else
2069
+ {
2070
+ entry4 = (int32 ) i ;
2071
+ pentry = & entry4 ;
2072
+ }
2073
+
2074
+ copyToBuffer (buffer , kvmap_offset + values [i ].index * kvmap_entry_size ,
2075
+ pentry , kvmap_entry_size );
2076
+ }
2077
+
2078
+ if ((kvmap_entry_size * nPairs ) % ALIGNOF_INT )
2079
+ memset (buffer -> data + kvmap_offset + kvmap_entry_size * nPairs , 0 ,
2080
+ ALIGNOF_INT - (kvmap_entry_size * nPairs ) % ALIGNOF_INT );
2019
2081
}
2020
2082
2021
2083
/*
@@ -2607,9 +2669,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
2607
2669
int count = container -> header & JB_CMASK ;
2608
2670
/* Since this is an object, account for *Pairs* of Jentrys */
2609
2671
bool sorted_values = (container -> header & JB_TMASK ) == JB_TOBJECT_SORTED ;
2610
- char * base_addr = (char * ) (children + count * 2 ) + ( sorted_values ? sizeof ( uint32 ) * count : 0 ) ;
2611
- uint32 * kvmap = sorted_values ? & container -> children [ count * 2 ] : NULL ;
2612
- Size base_offset = base_addr - ( char * ) jb ;
2672
+ char * base_addr = (char * ) (children + count * 2 );
2673
+ JsonbKVMap kvmap ;
2674
+ Size base_offset ;
2613
2675
uint32 stopLow = 0 ,
2614
2676
stopHigh = count ;
2615
2677
@@ -2619,6 +2681,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
2619
2681
if (count <= 0 )
2620
2682
return NULL ;
2621
2683
2684
+ base_addr = initKVMap (& kvmap , base_addr , count , sorted_values );
2685
+ base_offset = base_addr - (char * ) jb ;
2686
+
2622
2687
key .type = jbvString ;
2623
2688
key .val .string .val = keystr ;
2624
2689
key .val .string .len = keylen ;
@@ -2650,7 +2715,7 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
2650
2715
if (difference == 0 )
2651
2716
{
2652
2717
/* Found our key, return corresponding value */
2653
- int index = ( sorted_values ? kvmap [ stopMiddle ] : stopMiddle ) + count ;
2718
+ int index = JSONB_KVMAP_ENTRY ( & kvmap , stopMiddle ) + count ;
2654
2719
2655
2720
return fillCompressedJsonbValue (cjb , container , index , base_addr ,
2656
2721
getJsonbOffset (container , index ),
0 commit comments