@@ -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 ;
@@ -549,6 +570,24 @@ JsonFindValueInContainer(JsonContainer *json, uint32 flags, JsonValue *key)
549
570
return NULL ;
550
571
}
551
572
573
+ static void *
574
+ initKVMap (JsonbKVMap * kvmap ,void * pentries ,int field_count ,bool sorted )
575
+ {
576
+ if (sorted )
577
+ {
578
+ kvmap -> map .entries = pentries ;
579
+ kvmap -> entry_size = JSONB_KVMAP_ENTRY_SIZE (field_count );
580
+
581
+ return (char * )pentries + INTALIGN (field_count * kvmap -> entry_size );
582
+ }
583
+ else
584
+ {
585
+ kvmap -> entry_size = 0 ;
586
+
587
+ return pentries ;
588
+ }
589
+ }
590
+
552
591
/*
553
592
* Find value by key in Jsonb object and fetch it into 'res', which is also
554
593
* returned.
@@ -562,9 +601,9 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
562
601
const JsonbContainer * container = JsonContainerDataPtr (jsc );
563
602
const JEntry * children = container -> children ;
564
603
int count = JsonContainerSize (jsc );
565
- char * baseAddr ;
604
+ char * baseAddr = ( char * ) ( children + count * 2 ) ;
566
605
bool sorted_values = (container -> header & JB_TMASK )== JB_TOBJECT_SORTED ;
567
- const uint32 * kvmap ;
606
+ JsonbKVMap kvmap ;
568
607
uint32 stopLow ,
569
608
stopHigh ;
570
609
@@ -578,16 +617,8 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
578
617
* Binary search the container. Since we know this is an object, account
579
618
* for *Pairs* of Jentrys
580
619
*/
581
- if (sorted_values )
582
- {
583
- kvmap = & children [count * 2 ];
584
- baseAddr = (char * )& kvmap [count ];
585
- }
586
- else
587
- {
588
- kvmap = NULL ;
589
- baseAddr = (char * ) (children + count * 2 );
590
- }
620
+ baseAddr = initKVMap (& kvmap ,baseAddr ,count ,sorted_values );
621
+
591
622
stopLow = 0 ;
592
623
stopHigh = count ;
593
624
while (stopLow < stopHigh )
@@ -608,7 +639,7 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
608
639
if (difference == 0 )
609
640
{
610
641
/* Found our key, return corresponding value */
611
- int index = ( sorted_values ? kvmap [ stopMiddle ] : stopMiddle )+ count ;
642
+ int index = JSONB_KVMAP_ENTRY ( & kvmap , stopMiddle )+ count ;
612
643
613
644
if (!res )
614
645
res = palloc (sizeof (JsonbValue ));
@@ -1097,6 +1128,7 @@ JsonbIteratorToken
1097
1128
JsonbIteratorNext (JsonIterator * * jsit ,JsonbValue * val ,bool skipNested )
1098
1129
{
1099
1130
JsonbIterator * * it = (JsonbIterator * * )jsit ;
1131
+ int entry_index ;
1100
1132
1101
1133
if (* it == NULL )
1102
1134
return WJB_DONE ;
@@ -1209,17 +1241,19 @@ JsonbIteratorNext(JsonIterator **jsit, JsonbValue *val, bool skipNested)
1209
1241
/* Set state for next call */
1210
1242
(* it )-> state = JBI_OBJECT_KEY ;
1211
1243
1244
+ entry_index = JSONB_KVMAP_ENTRY (& (* it )-> kvmap , (* it )-> curIndex )+ (* it )-> nElems ;
1245
+
1212
1246
fillCompressedJsonbValue ((* it )-> compressed , (* it )-> container ,
1213
- (( * it ) -> kvMap ? ( * it ) -> kvMap [( * it ) -> curIndex ] : ( * it ) -> curIndex ) + ( * it ) -> nElems ,
1247
+ entry_index ,
1214
1248
(* it )-> dataProper ,
1215
- (* it )-> kvMap ?
1216
- getJsonbOffset ((* it )-> container ,( * it ) -> kvMap [( * it ) -> curIndex ] + ( * it ) -> nElems ) :
1249
+ (* it )-> kvmap . entry_size ?
1250
+ getJsonbOffset ((* it )-> container ,entry_index ) :
1217
1251
(* it )-> curValueOffset ,
1218
1252
val );
1219
1253
1220
1254
JBE_ADVANCE_OFFSET ((* it )-> curDataOffset ,
1221
1255
(* it )-> children [(* it )-> curIndex ]);
1222
- if (!(* it )-> kvMap )
1256
+ if (!(* it )-> kvmap . entry_size )
1223
1257
JBE_ADVANCE_OFFSET ((* it )-> curValueOffset ,
1224
1258
(* it )-> children [(* it )-> curIndex + (* it )-> nElems ]);
1225
1259
(* it )-> curIndex ++ ;
@@ -1261,6 +1295,7 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
1261
1295
struct CompressedJsonb * cjb )
1262
1296
{
1263
1297
JsonbIterator * it ;
1298
+ int type = container -> header & JB_TMASK ;
1264
1299
1265
1300
it = palloc0 (sizeof (JsonbIterator ));
1266
1301
it -> ji .container = cont ;
@@ -1273,7 +1308,7 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
1273
1308
/* Array starts just after header */
1274
1309
it -> children = container -> children ;
1275
1310
1276
- switch (container -> header & JB_TMASK )
1311
+ switch (type )
1277
1312
{
1278
1313
case JB_TSCALAR :
1279
1314
it -> isScalar = true;
@@ -1288,16 +1323,12 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
1288
1323
break ;
1289
1324
1290
1325
case JB_TOBJECT :
1291
- it -> kvMap = NULL ;
1326
+ case JB_TOBJECT_SORTED :
1292
1327
it -> dataProper =
1293
1328
(char * )it -> children + it -> nElems * sizeof (JEntry )* 2 ;
1294
- it -> state = JBI_OBJECT_START ;
1295
- break ;
1329
+ it -> dataProper = initKVMap ( & it -> kvmap , it -> dataProper , it -> nElems ,
1330
+ type == JB_TOBJECT_SORTED ) ;
1296
1331
1297
- case JB_TOBJECT_SORTED :
1298
- it -> kvMap = (uint32 * )
1299
- ((char * )it -> children + it -> nElems * sizeof (JEntry )* 2 );
1300
- it -> dataProper = (char * )& it -> kvMap [it -> nElems ];
1301
1332
it -> state = JBI_OBJECT_START ;
1302
1333
break ;
1303
1334
@@ -2021,6 +2052,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
2021
2052
uint32 header ;
2022
2053
int nPairs = val -> val .object .nPairs ;
2023
2054
int reserved_size ;
2055
+ int kvmap_entry_size ;
2024
2056
bool sorted_values = jsonb_sort_field_values && nPairs > 1 ;
2025
2057
struct
2026
2058
{
@@ -2047,6 +2079,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
2047
2079
{
2048
2080
if (values [i ].index != i )
2049
2081
{
2082
+ kvmap_entry_size = JSONB_KVMAP_ENTRY_SIZE (nPairs );
2050
2083
sorted_values = true;
2051
2084
break ;
2052
2085
}
@@ -2069,16 +2102,45 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
2069
2102
/* Reserve space for the JEntries of the keys and values. */
2070
2103
reserved_size = sizeof (JEntry )* nPairs * 2 ;
2071
2104
if (sorted_values )
2072
- reserved_size += sizeof ( int32 ) * nPairs ;
2105
+ reserved_size += INTALIGN ( kvmap_entry_size * nPairs ) ;
2073
2106
2074
2107
jentry_offset = reserveFromBuffer (buffer ,reserved_size );
2075
2108
2076
2109
/* Write key-value map */
2077
2110
if (sorted_values )
2078
2111
{
2112
+ int kvmap_offset = jentry_offset + sizeof (JEntry )* nPairs * 2 ;
2113
+
2079
2114
for (i = 0 ;i < nPairs ;i ++ )
2080
- copyToBuffer (buffer ,jentry_offset + sizeof (JEntry )* nPairs * 2 + values [i ].index * sizeof (int32 ),
2081
- & i ,sizeof (int32 ));
2115
+ {
2116
+ uint8 entry1 ;
2117
+ uint16 entry2 ;
2118
+ uint32 entry4 ;
2119
+ void * pentry ;
2120
+
2121
+ if (kvmap_entry_size == 1 )
2122
+ {
2123
+ entry1 = (uint8 )i ;
2124
+ pentry = & entry1 ;
2125
+ }
2126
+ else if (kvmap_entry_size == 2 )
2127
+ {
2128
+ entry2 = (uint16 )i ;
2129
+ pentry = & entry2 ;
2130
+ }
2131
+ else
2132
+ {
2133
+ entry4 = (int32 )i ;
2134
+ pentry = & entry4 ;
2135
+ }
2136
+
2137
+ copyToBuffer (buffer ,kvmap_offset + values [i ].index * kvmap_entry_size ,
2138
+ pentry ,kvmap_entry_size );
2139
+ }
2140
+
2141
+ if ((kvmap_entry_size * nPairs ) %ALIGNOF_INT )
2142
+ memset (buffer -> data + kvmap_offset + kvmap_entry_size * nPairs ,0 ,
2143
+ ALIGNOF_INT - (kvmap_entry_size * nPairs ) %ALIGNOF_INT );
2082
2144
}
2083
2145
2084
2146
/*
@@ -2670,9 +2732,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
2670
2732
int count = container -> header & JB_CMASK ;
2671
2733
/* Since this is an object, account for *Pairs* of Jentrys */
2672
2734
bool sorted_values = (container -> header & JB_TMASK )== JB_TOBJECT_SORTED ;
2673
- char * base_addr = (char * ) (children + count * 2 )+ ( sorted_values ? sizeof ( uint32 ) * count : 0 ) ;
2674
- uint32 * kvmap = sorted_values ? & container -> children [ count * 2 ] : NULL ;
2675
- Size base_offset = base_addr - ( char * ) jb ;
2735
+ char * base_addr = (char * ) (children + count * 2 );
2736
+ JsonbKVMap kvmap ;
2737
+ Size base_offset ;
2676
2738
uint32 stopLow = 0 ,
2677
2739
stopHigh = count ;
2678
2740
@@ -2682,6 +2744,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
2682
2744
if (count <=0 )
2683
2745
return NULL ;
2684
2746
2747
+ base_addr = initKVMap (& kvmap ,base_addr ,count ,sorted_values );
2748
+ base_offset = base_addr - (char * )jb ;
2749
+
2685
2750
key .type = jbvString ;
2686
2751
key .val .string .val = keystr ;
2687
2752
key .val .string .len = keylen ;
@@ -2713,7 +2778,7 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
2713
2778
if (difference == 0 )
2714
2779
{
2715
2780
/* Found our key, return corresponding value */
2716
- int index = ( sorted_values ? kvmap [ stopMiddle ] : stopMiddle )+ count ;
2781
+ int index = JSONB_KVMAP_ENTRY ( & kvmap , stopMiddle )+ count ;
2717
2782
2718
2783
return fillCompressedJsonbValue (cjb ,container ,index ,base_addr ,
2719
2784
getJsonbOffset (container ,index ),