@@ -67,6 +67,27 @@ typedef struct CompressedJsonb
67
67
int offset ;
68
68
} CompressedJsonb ;
69
69
70
+ typedef struct JsonbKVMap
71
+ {
72
+ union
73
+ {
74
+ const uint8 * entries1 ;
75
+ const uint16 * entries2 ;
76
+ const int32 * entries4 ;
77
+ const void * entries ;
78
+ } map ;
79
+ int entry_size ;
80
+ } JsonbKVMap ;
81
+
82
+ #define JSONB_KVMAP_ENTRY_SIZE (nPairs ) \
83
+ ((nPairs) < 256 ? 1 : (nPairs) < 65536 ? 2 : 4)
84
+
85
+ #define JSONB_KVMAP_ENTRY (kvmap , index ) \
86
+ (!(kvmap)->entry_size ? (index) : \
87
+ (kvmap)->entry_size == 1 ? (int32) (kvmap)->map.entries1[index] : \
88
+ (kvmap)->entry_size == 2 ? (int32) (kvmap)->map.entries2[index] : \
89
+ (kvmap)->map.entries4[index])
90
+
70
91
typedef struct jsonbIterator
71
92
{
72
93
JsonIterator ji ;
@@ -82,7 +103,7 @@ typedef struct jsonbIterator
82
103
const JEntry * children ; /* JEntrys for child nodes */
83
104
/* Data proper. This points to the beginning of the variable-length data */
84
105
char * dataProper ;
85
- uint32 * kvMap ;
106
+ JsonbKVMap kvmap ;
86
107
87
108
/* Current item in buffer (up to nElems) */
88
109
int curIndex ;
@@ -544,6 +565,24 @@ JsonFindValueInContainer(JsonContainer *json, uint32 flags, JsonValue *key)
544
565
return NULL ;
545
566
}
546
567
568
+ static void *
569
+ initKVMap (JsonbKVMap * kvmap , void * pentries , int field_count , bool sorted )
570
+ {
571
+ if (sorted )
572
+ {
573
+ kvmap -> map .entries = pentries ;
574
+ kvmap -> entry_size = JSONB_KVMAP_ENTRY_SIZE (field_count );
575
+
576
+ return (char * ) pentries + INTALIGN (field_count * kvmap -> entry_size );
577
+ }
578
+ else
579
+ {
580
+ kvmap -> entry_size = 0 ;
581
+
582
+ return pentries ;
583
+ }
584
+ }
585
+
547
586
/*
548
587
* Find value by key in Jsonb object and fetch it into 'res', which is also
549
588
* returned.
@@ -557,9 +596,9 @@ jsonbFindKeyInObject(JsonContainer *jsc, const char *keyVal, int keyLen,
557
596
const JsonbContainerHeader * container = JsonContainerDataPtr (jsc );
558
597
const JEntry * children = container -> children ;
559
598
int count = JsonContainerSize (jsc );
560
- char * baseAddr ;
599
+ char * baseAddr = ( char * ) ( children + count * 2 ) ;
561
600
bool sorted_values = (container -> header & JBC_TMASK ) == JBC_TOBJECT_SORTED ;
562
- const uint32 * kvmap ;
601
+ JsonbKVMap kvmap ;
563
602
uint32 stopLow ,
564
603
stopHigh ;
565
604
@@ -573,16 +612,8 @@ jsonbFindKeyInObject(JsonContainer *jsc, const char *keyVal, int keyLen,
573
612
* Binary search the container. Since we know this is an object, account
574
613
* for *Pairs* of Jentrys
575
614
*/
576
- if (sorted_values )
577
- {
578
- kvmap = & children [count * 2 ];
579
- baseAddr = (char * ) & kvmap [count ];
580
- }
581
- else
582
- {
583
- kvmap = NULL ;
584
- baseAddr = (char * ) (children + count * 2 );
585
- }
615
+ baseAddr = initKVMap (& kvmap , baseAddr , count , sorted_values );
616
+
586
617
stopLow = 0 ;
587
618
stopHigh = count ;
588
619
while (stopLow < stopHigh )
@@ -603,7 +634,7 @@ jsonbFindKeyInObject(JsonContainer *jsc, const char *keyVal, int keyLen,
603
634
if (difference == 0 )
604
635
{
605
636
/* Found our key, return corresponding value */
606
- int index = ( sorted_values ? kvmap [ stopMiddle ] : stopMiddle ) + count ;
637
+ int index = JSONB_KVMAP_ENTRY ( & kvmap , stopMiddle ) + count ;
607
638
608
639
if (!res )
609
640
res = palloc (sizeof (JsonbValue ));
@@ -1099,6 +1130,7 @@ static JsonbIteratorToken
1099
1130
jsonbIteratorNext (JsonIterator * * jsit , JsonbValue * val , bool skipNested )
1100
1131
{
1101
1132
jsonbIterator * * it = (jsonbIterator * * ) jsit ;
1133
+ int entry_index ;
1102
1134
1103
1135
if (* it == NULL )
1104
1136
return WJB_DONE ;
@@ -1215,17 +1247,19 @@ jsonbIteratorNext(JsonIterator **jsit, JsonbValue *val, bool skipNested)
1215
1247
/* Set state for next call */
1216
1248
(* it )-> state = JBI_OBJECT_KEY ;
1217
1249
1250
+ entry_index = JSONB_KVMAP_ENTRY (& (* it )-> kvmap , (* it )-> curIndex ) + (* it )-> nElems ;
1251
+
1218
1252
fillCompressedJsonbValue ((* it )-> compressed , (* it )-> container ,
1219
- (( * it ) -> kvMap ? ( * it ) -> kvMap [( * it ) -> curIndex ] : ( * it ) -> curIndex ) + ( * it ) -> nElems ,
1253
+ entry_index ,
1220
1254
(* it )-> dataProper ,
1221
- (* it )-> kvMap ?
1222
- getJsonbOffset ((* it )-> container , ( * it ) -> kvMap [( * it ) -> curIndex ] + ( * it ) -> nElems ) :
1255
+ (* it )-> kvmap . entry_size ?
1256
+ getJsonbOffset ((* it )-> container , entry_index ) :
1223
1257
(* it )-> curValueOffset ,
1224
1258
val );
1225
1259
1226
1260
JBE_ADVANCE_OFFSET ((* it )-> curDataOffset ,
1227
1261
(* it )-> children [(* it )-> curIndex ]);
1228
- if (!(* it )-> kvMap )
1262
+ if (!(* it )-> kvmap . entry_size )
1229
1263
JBE_ADVANCE_OFFSET ((* it )-> curValueOffset ,
1230
1264
(* it )-> children [(* it )-> curIndex + (* it )-> nElems ]);
1231
1265
(* it )-> curIndex ++ ;
@@ -1268,6 +1302,7 @@ jsonbIteratorInitExt(JsonContainer *cont,
1268
1302
struct CompressedJsonb * cjb )
1269
1303
{
1270
1304
jsonbIterator * it ;
1305
+ int type = container -> header & JBC_TMASK ;
1271
1306
1272
1307
it = palloc0 (sizeof (jsonbIterator ));
1273
1308
it -> ji .container = cont ;
@@ -1280,7 +1315,7 @@ jsonbIteratorInitExt(JsonContainer *cont,
1280
1315
/* Array starts just after header */
1281
1316
it -> children = container -> children ;
1282
1317
1283
- switch (container -> header & JBC_TMASK )
1318
+ switch (type )
1284
1319
{
1285
1320
case JBC_TSCALAR :
1286
1321
it -> isScalar = true;
@@ -1295,16 +1330,12 @@ jsonbIteratorInitExt(JsonContainer *cont,
1295
1330
break ;
1296
1331
1297
1332
case JBC_TOBJECT :
1298
- it -> kvMap = NULL ;
1333
+ case JBC_TOBJECT_SORTED :
1299
1334
it -> dataProper =
1300
1335
(char * ) it -> children + it -> nElems * sizeof (JEntry ) * 2 ;
1301
- it -> state = JBI_OBJECT_START ;
1302
- break ;
1336
+ it -> dataProper = initKVMap ( & it -> kvmap , it -> dataProper , it -> nElems ,
1337
+ type == JBC_TOBJECT_SORTED ) ;
1303
1338
1304
- case JBC_TOBJECT_SORTED :
1305
- it -> kvMap = (uint32 * )
1306
- ((char * ) it -> children + it -> nElems * sizeof (JEntry ) * 2 );
1307
- it -> dataProper = (char * ) & it -> kvMap [it -> nElems ];
1308
1339
it -> state = JBI_OBJECT_START ;
1309
1340
break ;
1310
1341
@@ -2031,6 +2062,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
2031
2062
uint32 header ;
2032
2063
int nPairs = val -> val .object .nPairs ;
2033
2064
int reserved_size ;
2065
+ int kvmap_entry_size ;
2034
2066
bool sorted_values = jsonb_sort_field_values && nPairs > 1 ;
2035
2067
struct
2036
2068
{
@@ -2057,6 +2089,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
2057
2089
{
2058
2090
if (values [i ].index != i )
2059
2091
{
2092
+ kvmap_entry_size = JSONB_KVMAP_ENTRY_SIZE (nPairs );
2060
2093
sorted_values = true;
2061
2094
break ;
2062
2095
}
@@ -2079,16 +2112,45 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
2079
2112
/* Reserve space for the JEntries of the keys and values. */
2080
2113
reserved_size = sizeof (JEntry ) * nPairs * 2 ;
2081
2114
if (sorted_values )
2082
- reserved_size += sizeof ( int32 ) * nPairs ;
2115
+ reserved_size += INTALIGN ( kvmap_entry_size * nPairs ) ;
2083
2116
2084
2117
jentry_offset = reserveFromBuffer (buffer , reserved_size );
2085
2118
2086
2119
/* Write key-value map */
2087
2120
if (sorted_values )
2088
2121
{
2122
+ int kvmap_offset = jentry_offset + sizeof (JEntry ) * nPairs * 2 ;
2123
+
2089
2124
for (i = 0 ; i < nPairs ; i ++ )
2090
- copyToBuffer (buffer , jentry_offset + sizeof (JEntry ) * nPairs * 2 + values [i ].index * sizeof (int32 ),
2091
- (void * ) & i , sizeof (int32 ));
2125
+ {
2126
+ uint8 entry1 ;
2127
+ uint16 entry2 ;
2128
+ uint32 entry4 ;
2129
+ void * pentry ;
2130
+
2131
+ if (kvmap_entry_size == 1 )
2132
+ {
2133
+ entry1 = (uint8 ) i ;
2134
+ pentry = & entry1 ;
2135
+ }
2136
+ else if (kvmap_entry_size == 2 )
2137
+ {
2138
+ entry2 = (uint16 ) i ;
2139
+ pentry = & entry2 ;
2140
+ }
2141
+ else
2142
+ {
2143
+ entry4 = (int32 ) i ;
2144
+ pentry = & entry4 ;
2145
+ }
2146
+
2147
+ copyToBuffer (buffer , kvmap_offset + values [i ].index * kvmap_entry_size ,
2148
+ pentry , kvmap_entry_size );
2149
+ }
2150
+
2151
+ if ((kvmap_entry_size * nPairs ) % ALIGNOF_INT )
2152
+ memset (buffer -> data + kvmap_offset + kvmap_entry_size * nPairs , 0 ,
2153
+ ALIGNOF_INT - (kvmap_entry_size * nPairs ) % ALIGNOF_INT );
2092
2154
}
2093
2155
2094
2156
/*
@@ -2614,9 +2676,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
2614
2676
int count = container -> header & JBC_CMASK ;
2615
2677
/* Since this is an object, account for *Pairs* of Jentrys */
2616
2678
bool sorted_values = (container -> header & JBC_TMASK ) == JBC_TOBJECT_SORTED ;
2617
- char * base_addr = (char * ) (children + count * 2 ) + ( sorted_values ? sizeof ( uint32 ) * count : 0 ) ;
2618
- uint32 * kvmap = sorted_values ? & container -> children [ count * 2 ] : NULL ;
2619
- Size base_offset = base_addr - ( char * ) jb ;
2679
+ char * base_addr = (char * ) (children + count * 2 );
2680
+ JsonbKVMap kvmap ;
2681
+ Size base_offset ;
2620
2682
uint32 stopLow = 0 ,
2621
2683
stopHigh = count ;
2622
2684
@@ -2627,6 +2689,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
2627
2689
if (count <= 0 )
2628
2690
return NULL ;
2629
2691
2692
+ base_addr = initKVMap (& kvmap , base_addr , count , sorted_values );
2693
+ base_offset = base_addr - (char * ) jb ;
2694
+
2630
2695
key .type = jbvString ;
2631
2696
key .val .string .val = keystr ;
2632
2697
key .val .string .len = keylen ;
@@ -2658,7 +2723,7 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
2658
2723
if (difference == 0 )
2659
2724
{
2660
2725
/* Found our key, return corresponding value */
2661
- int index = ( sorted_values ? kvmap [ stopMiddle ] : stopMiddle ) + count ;
2726
+ int index = JSONB_KVMAP_ENTRY ( & kvmap , stopMiddle ) + count ;
2662
2727
2663
2728
if (!res )
2664
2729
res = palloc (sizeof (* res ));
0 commit comments