@@ -67,6 +67,27 @@ typedef struct CompressedJsonb
6767 int offset ;
6868} CompressedJsonb ;
6969
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+
7091typedef struct jsonbIterator
7192{
7293 JsonIterator ji ;
@@ -82,7 +103,7 @@ typedef struct jsonbIterator
82103 const JEntry * children ; /* JEntrys for child nodes */
83104 /* Data proper. This points to the beginning of the variable-length data */
84105 char * dataProper ;
85- uint32 * kvMap ;
106+ JsonbKVMap kvmap ;
86107
87108 /* Current item in buffer (up to nElems) */
88109 int curIndex ;
@@ -544,6 +565,24 @@ JsonFindValueInContainer(JsonContainer *json, uint32 flags, JsonValue *key)
544565 return NULL ;
545566}
546567
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+
547586/*
548587 * Find value by key in Jsonb object and fetch it into 'res', which is also
549588 * returned.
@@ -557,9 +596,9 @@ jsonbFindKeyInObject(JsonContainer *jsc, const char *keyVal, int keyLen,
557596 const JsonbContainerHeader * container = JsonContainerDataPtr (jsc );
558597 const JEntry * children = container -> children ;
559598 int count = JsonContainerSize (jsc );
560- char * baseAddr ;
599+ char * baseAddr = ( char * ) ( children + count * 2 ) ;
561600 bool sorted_values = (container -> header & JBC_TMASK ) == JBC_TOBJECT_SORTED ;
562- const uint32 * kvmap ;
601+ JsonbKVMap kvmap ;
563602 uint32 stopLow ,
564603 stopHigh ;
565604
@@ -573,16 +612,8 @@ jsonbFindKeyInObject(JsonContainer *jsc, const char *keyVal, int keyLen,
573612 * Binary search the container. Since we know this is an object, account
574613 * for *Pairs* of Jentrys
575614 */
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+
586617 stopLow = 0 ;
587618 stopHigh = count ;
588619 while (stopLow < stopHigh )
@@ -603,7 +634,7 @@ jsonbFindKeyInObject(JsonContainer *jsc, const char *keyVal, int keyLen,
603634 if (difference == 0 )
604635 {
605636 /* Found our key, return corresponding value */
606- int index = ( sorted_values ? kvmap [ stopMiddle ] : stopMiddle ) + count ;
637+ int index = JSONB_KVMAP_ENTRY ( & kvmap , stopMiddle ) + count ;
607638
608639 if (!res )
609640 res = palloc (sizeof (JsonbValue ));
@@ -1099,6 +1130,7 @@ static JsonbIteratorToken
10991130jsonbIteratorNext (JsonIterator * * jsit , JsonbValue * val , bool skipNested )
11001131{
11011132 jsonbIterator * * it = (jsonbIterator * * ) jsit ;
1133+ int entry_index ;
11021134
11031135 if (* it == NULL )
11041136 return WJB_DONE ;
@@ -1215,17 +1247,19 @@ jsonbIteratorNext(JsonIterator **jsit, JsonbValue *val, bool skipNested)
12151247 /* Set state for next call */
12161248 (* it )-> state = JBI_OBJECT_KEY ;
12171249
1250+ entry_index = JSONB_KVMAP_ENTRY (& (* it )-> kvmap , (* it )-> curIndex ) + (* it )-> nElems ;
1251+
12181252 fillCompressedJsonbValue ((* it )-> compressed , (* it )-> container ,
1219- (( * it ) -> kvMap ? ( * it ) -> kvMap [( * it ) -> curIndex ] : ( * it ) -> curIndex ) + ( * it ) -> nElems ,
1253+ entry_index ,
12201254 (* 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 ) :
12231257 (* it )-> curValueOffset ,
12241258 val );
12251259
12261260 JBE_ADVANCE_OFFSET ((* it )-> curDataOffset ,
12271261 (* it )-> children [(* it )-> curIndex ]);
1228- if (!(* it )-> kvMap )
1262+ if (!(* it )-> kvmap . entry_size )
12291263 JBE_ADVANCE_OFFSET ((* it )-> curValueOffset ,
12301264 (* it )-> children [(* it )-> curIndex + (* it )-> nElems ]);
12311265 (* it )-> curIndex ++ ;
@@ -1268,6 +1302,7 @@ jsonbIteratorInitExt(JsonContainer *cont,
12681302 struct CompressedJsonb * cjb )
12691303{
12701304 jsonbIterator * it ;
1305+ int type = container -> header & JBC_TMASK ;
12711306
12721307 it = palloc0 (sizeof (jsonbIterator ));
12731308 it -> ji .container = cont ;
@@ -1280,7 +1315,7 @@ jsonbIteratorInitExt(JsonContainer *cont,
12801315 /* Array starts just after header */
12811316 it -> children = container -> children ;
12821317
1283- switch (container -> header & JBC_TMASK )
1318+ switch (type )
12841319 {
12851320 case JBC_TSCALAR :
12861321 it -> isScalar = true;
@@ -1295,16 +1330,12 @@ jsonbIteratorInitExt(JsonContainer *cont,
12951330 break ;
12961331
12971332 case JBC_TOBJECT :
1298- it -> kvMap = NULL ;
1333+ case JBC_TOBJECT_SORTED :
12991334 it -> dataProper =
13001335 (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 ) ;
13031338
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 ];
13081339 it -> state = JBI_OBJECT_START ;
13091340 break ;
13101341
@@ -2031,6 +2062,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20312062 uint32 header ;
20322063 int nPairs = val -> val .object .nPairs ;
20332064 int reserved_size ;
2065+ int kvmap_entry_size ;
20342066 bool sorted_values = jsonb_sort_field_values && nPairs > 1 ;
20352067 struct
20362068 {
@@ -2057,6 +2089,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20572089 {
20582090 if (values [i ].index != i )
20592091 {
2092+ kvmap_entry_size = JSONB_KVMAP_ENTRY_SIZE (nPairs );
20602093 sorted_values = true;
20612094 break ;
20622095 }
@@ -2079,16 +2112,45 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20792112 /* Reserve space for the JEntries of the keys and values. */
20802113 reserved_size = sizeof (JEntry ) * nPairs * 2 ;
20812114 if (sorted_values )
2082- reserved_size += sizeof ( int32 ) * nPairs ;
2115+ reserved_size += INTALIGN ( kvmap_entry_size * nPairs ) ;
20832116
20842117 jentry_offset = reserveFromBuffer (buffer , reserved_size );
20852118
20862119 /* Write key-value map */
20872120 if (sorted_values )
20882121 {
2122+ int kvmap_offset = jentry_offset + sizeof (JEntry ) * nPairs * 2 ;
2123+
20892124 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 );
20922154 }
20932155
20942156 /*
@@ -2614,9 +2676,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26142676 int count = container -> header & JBC_CMASK ;
26152677 /* Since this is an object, account for *Pairs* of Jentrys */
26162678 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 ;
26202682 uint32 stopLow = 0 ,
26212683 stopHigh = count ;
26222684
@@ -2627,6 +2689,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26272689 if (count <= 0 )
26282690 return NULL ;
26292691
2692+ base_addr = initKVMap (& kvmap , base_addr , count , sorted_values );
2693+ base_offset = base_addr - (char * ) jb ;
2694+
26302695 key .type = jbvString ;
26312696 key .val .string .val = keystr ;
26322697 key .val .string .len = keylen ;
@@ -2658,7 +2723,7 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26582723 if (difference == 0 )
26592724 {
26602725 /* Found our key, return corresponding value */
2661- int index = ( sorted_values ? kvmap [ stopMiddle ] : stopMiddle ) + count ;
2726+ int index = JSONB_KVMAP_ENTRY ( & kvmap , stopMiddle ) + count ;
26622727
26632728 if (!res )
26642729 res = palloc (sizeof (* res ));
0 commit comments