@@ -66,6 +66,27 @@ typedef struct CompressedJsonb
6666 int offset ;
6767} CompressedJsonb ;
6868
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+
6990struct JsonbIterator
7091{
7192 JsonIterator ji ;
@@ -81,7 +102,7 @@ struct JsonbIterator
81102 const JEntry * children ; /* JEntrys for child nodes */
82103 /* Data proper. This points to the beginning of the variable-length data */
83104 char * dataProper ;
84- uint32 * kvMap ;
105+ JsonbKVMap kvmap ;
85106
86107 /* Current item in buffer (up to nElems) */
87108 int curIndex ;
@@ -550,6 +571,24 @@ JsonFindValueInContainer(JsonContainer *json, uint32 flags, JsonValue *key)
550571 return NULL ;
551572}
552573
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+
553592/*
554593 * Find value by key in Jsonb object and fetch it into 'res', which is also
555594 * returned.
@@ -563,9 +602,9 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
563602 const JsonbContainer * container = JsonContainerDataPtr (jsc );
564603 const JEntry * children = container -> children ;
565604 int count = JsonContainerSize (jsc );
566- char * baseAddr ;
605+ char * baseAddr = ( char * ) ( children + count * 2 ) ;
567606 bool sorted_values = (container -> header & JB_TMASK ) == JB_TOBJECT_SORTED ;
568- const uint32 * kvmap ;
607+ JsonbKVMap kvmap ;
569608 uint32 stopLow ,
570609 stopHigh ;
571610
@@ -579,16 +618,8 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
579618 * Binary search the container. Since we know this is an object, account
580619 * for *Pairs* of Jentrys
581620 */
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+
592623 stopLow = 0 ;
593624 stopHigh = count ;
594625 while (stopLow < stopHigh )
@@ -609,7 +640,7 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
609640 if (difference == 0 )
610641 {
611642 /* Found our key, return corresponding value */
612- int index = ( sorted_values ? kvmap [ stopMiddle ] : stopMiddle ) + count ;
643+ int index = JSONB_KVMAP_ENTRY ( & kvmap , stopMiddle ) + count ;
613644
614645 if (!res )
615646 res = palloc (sizeof (JsonbValue ));
@@ -1034,6 +1065,7 @@ JsonbIteratorToken
10341065JsonbIteratorNext (JsonIterator * * jsit , JsonbValue * val , bool skipNested )
10351066{
10361067 JsonbIterator * * it = (JsonbIterator * * ) jsit ;
1068+ int entry_index ;
10371069
10381070 if (* it == NULL )
10391071 return WJB_DONE ;
@@ -1146,17 +1178,19 @@ JsonbIteratorNext(JsonIterator **jsit, JsonbValue *val, bool skipNested)
11461178 /* Set state for next call */
11471179 (* it )-> state = JBI_OBJECT_KEY ;
11481180
1181+ entry_index = JSONB_KVMAP_ENTRY (& (* it )-> kvmap , (* it )-> curIndex ) + (* it )-> nElems ;
1182+
11491183 fillCompressedJsonbValue ((* it )-> compressed , (* it )-> container ,
1150- (( * it ) -> kvMap ? ( * it ) -> kvMap [( * it ) -> curIndex ] : ( * it ) -> curIndex ) + ( * it ) -> nElems ,
1184+ entry_index ,
11511185 (* 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 ) :
11541188 (* it )-> curValueOffset ,
11551189 val );
11561190
11571191 JBE_ADVANCE_OFFSET ((* it )-> curDataOffset ,
11581192 (* it )-> children [(* it )-> curIndex ]);
1159- if (!(* it )-> kvMap )
1193+ if (!(* it )-> kvmap . entry_size )
11601194 JBE_ADVANCE_OFFSET ((* it )-> curValueOffset ,
11611195 (* it )-> children [(* it )-> curIndex + (* it )-> nElems ]);
11621196 (* it )-> curIndex ++ ;
@@ -1198,6 +1232,7 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
11981232 struct CompressedJsonb * cjb )
11991233{
12001234 JsonbIterator * it ;
1235+ int type = container -> header & JB_TMASK ;
12011236
12021237 it = palloc0 (sizeof (JsonbIterator ));
12031238 it -> ji .container = cont ;
@@ -1210,7 +1245,7 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
12101245 /* Array starts just after header */
12111246 it -> children = container -> children ;
12121247
1213- switch (container -> header & JB_TMASK )
1248+ switch (type )
12141249 {
12151250 case JB_TSCALAR :
12161251 it -> isScalar = true;
@@ -1225,16 +1260,12 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
12251260 break ;
12261261
12271262 case JB_TOBJECT :
1228- it -> kvMap = NULL ;
1263+ case JB_TOBJECT_SORTED :
12291264 it -> dataProper =
12301265 (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 ) ;
12331268
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 ];
12381269 it -> state = JBI_OBJECT_START ;
12391270 break ;
12401271
@@ -1958,6 +1989,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
19581989 uint32 header ;
19591990 int nPairs = val -> val .object .nPairs ;
19601991 int reserved_size ;
1992+ int kvmap_entry_size ;
19611993 bool sorted_values = jsonb_sort_field_values && nPairs > 1 ;
19621994 struct
19631995 {
@@ -1984,6 +2016,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
19842016 {
19852017 if (values [i ].index != i )
19862018 {
2019+ kvmap_entry_size = JSONB_KVMAP_ENTRY_SIZE (nPairs );
19872020 sorted_values = true;
19882021 break ;
19892022 }
@@ -2006,16 +2039,45 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20062039 /* Reserve space for the JEntries of the keys and values. */
20072040 reserved_size = sizeof (JEntry ) * nPairs * 2 ;
20082041 if (sorted_values )
2009- reserved_size += sizeof ( int32 ) * nPairs ;
2042+ reserved_size += INTALIGN ( kvmap_entry_size * nPairs ) ;
20102043
20112044 jentry_offset = reserveFromBuffer (buffer , reserved_size );
20122045
20132046 /* Write key-value map */
20142047 if (sorted_values )
20152048 {
2049+ int kvmap_offset = jentry_offset + sizeof (JEntry ) * nPairs * 2 ;
2050+
20162051 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 );
20192081 }
20202082
20212083 /*
@@ -2607,9 +2669,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26072669 int count = container -> header & JB_CMASK ;
26082670 /* Since this is an object, account for *Pairs* of Jentrys */
26092671 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 ;
26132675 uint32 stopLow = 0 ,
26142676 stopHigh = count ;
26152677
@@ -2619,6 +2681,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26192681 if (count <= 0 )
26202682 return NULL ;
26212683
2684+ base_addr = initKVMap (& kvmap , base_addr , count , sorted_values );
2685+ base_offset = base_addr - (char * ) jb ;
2686+
26222687 key .type = jbvString ;
26232688 key .val .string .val = keystr ;
26242689 key .val .string .len = keylen ;
@@ -2650,7 +2715,7 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26502715 if (difference == 0 )
26512716 {
26522717 /* Found our key, return corresponding value */
2653- int index = ( sorted_values ? kvmap [ stopMiddle ] : stopMiddle ) + count ;
2718+ int index = JSONB_KVMAP_ENTRY ( & kvmap , stopMiddle ) + count ;
26542719
26552720 return fillCompressedJsonbValue (cjb , container , index , base_addr ,
26562721 getJsonbOffset (container , index ),
0 commit comments