@@ -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 ;
@@ -549,6 +570,24 @@ JsonFindValueInContainer(JsonContainer *json, uint32 flags, JsonValue *key)
549570 return NULL ;
550571}
551572
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+
552591/*
553592 * Find value by key in Jsonb object and fetch it into 'res', which is also
554593 * returned.
@@ -562,9 +601,9 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
562601 const JsonbContainer * container = JsonContainerDataPtr (jsc );
563602 const JEntry * children = container -> children ;
564603 int count = JsonContainerSize (jsc );
565- char * baseAddr ;
604+ char * baseAddr = ( char * ) ( children + count * 2 ) ;
566605 bool sorted_values = (container -> header & JB_TMASK ) == JB_TOBJECT_SORTED ;
567- const uint32 * kvmap ;
606+ JsonbKVMap kvmap ;
568607 uint32 stopLow ,
569608 stopHigh ;
570609
@@ -578,16 +617,8 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
578617 * Binary search the container. Since we know this is an object, account
579618 * for *Pairs* of Jentrys
580619 */
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+
591622 stopLow = 0 ;
592623 stopHigh = count ;
593624 while (stopLow < stopHigh )
@@ -608,7 +639,7 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
608639 if (difference == 0 )
609640 {
610641 /* Found our key, return corresponding value */
611- int index = ( sorted_values ? kvmap [ stopMiddle ] : stopMiddle ) + count ;
642+ int index = JSONB_KVMAP_ENTRY ( & kvmap , stopMiddle ) + count ;
612643
613644 if (!res )
614645 res = palloc (sizeof (JsonbValue ));
@@ -1097,6 +1128,7 @@ JsonbIteratorToken
10971128JsonbIteratorNext (JsonIterator * * jsit , JsonbValue * val , bool skipNested )
10981129{
10991130 JsonbIterator * * it = (JsonbIterator * * ) jsit ;
1131+ int entry_index ;
11001132
11011133 if (* it == NULL )
11021134 return WJB_DONE ;
@@ -1209,17 +1241,19 @@ JsonbIteratorNext(JsonIterator **jsit, JsonbValue *val, bool skipNested)
12091241 /* Set state for next call */
12101242 (* it )-> state = JBI_OBJECT_KEY ;
12111243
1244+ entry_index = JSONB_KVMAP_ENTRY (& (* it )-> kvmap , (* it )-> curIndex ) + (* it )-> nElems ;
1245+
12121246 fillCompressedJsonbValue ((* it )-> compressed , (* it )-> container ,
1213- (( * it ) -> kvMap ? ( * it ) -> kvMap [( * it ) -> curIndex ] : ( * it ) -> curIndex ) + ( * it ) -> nElems ,
1247+ entry_index ,
12141248 (* 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 ) :
12171251 (* it )-> curValueOffset ,
12181252 val );
12191253
12201254 JBE_ADVANCE_OFFSET ((* it )-> curDataOffset ,
12211255 (* it )-> children [(* it )-> curIndex ]);
1222- if (!(* it )-> kvMap )
1256+ if (!(* it )-> kvmap . entry_size )
12231257 JBE_ADVANCE_OFFSET ((* it )-> curValueOffset ,
12241258 (* it )-> children [(* it )-> curIndex + (* it )-> nElems ]);
12251259 (* it )-> curIndex ++ ;
@@ -1261,6 +1295,7 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
12611295 struct CompressedJsonb * cjb )
12621296{
12631297 JsonbIterator * it ;
1298+ int type = container -> header & JB_TMASK ;
12641299
12651300 it = palloc0 (sizeof (JsonbIterator ));
12661301 it -> ji .container = cont ;
@@ -1273,7 +1308,7 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
12731308 /* Array starts just after header */
12741309 it -> children = container -> children ;
12751310
1276- switch (container -> header & JB_TMASK )
1311+ switch (type )
12771312 {
12781313 case JB_TSCALAR :
12791314 it -> isScalar = true;
@@ -1288,16 +1323,12 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
12881323 break ;
12891324
12901325 case JB_TOBJECT :
1291- it -> kvMap = NULL ;
1326+ case JB_TOBJECT_SORTED :
12921327 it -> dataProper =
12931328 (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 ) ;
12961331
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 ];
13011332 it -> state = JBI_OBJECT_START ;
13021333 break ;
13031334
@@ -2021,6 +2052,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20212052 uint32 header ;
20222053 int nPairs = val -> val .object .nPairs ;
20232054 int reserved_size ;
2055+ int kvmap_entry_size ;
20242056 bool sorted_values = jsonb_sort_field_values && nPairs > 1 ;
20252057 struct
20262058 {
@@ -2047,6 +2079,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20472079 {
20482080 if (values [i ].index != i )
20492081 {
2082+ kvmap_entry_size = JSONB_KVMAP_ENTRY_SIZE (nPairs );
20502083 sorted_values = true;
20512084 break ;
20522085 }
@@ -2069,16 +2102,45 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20692102 /* Reserve space for the JEntries of the keys and values. */
20702103 reserved_size = sizeof (JEntry ) * nPairs * 2 ;
20712104 if (sorted_values )
2072- reserved_size += sizeof ( int32 ) * nPairs ;
2105+ reserved_size += INTALIGN ( kvmap_entry_size * nPairs ) ;
20732106
20742107 jentry_offset = reserveFromBuffer (buffer , reserved_size );
20752108
20762109 /* Write key-value map */
20772110 if (sorted_values )
20782111 {
2112+ int kvmap_offset = jentry_offset + sizeof (JEntry ) * nPairs * 2 ;
2113+
20792114 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 );
20822144 }
20832145
20842146 /*
@@ -2670,9 +2732,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26702732 int count = container -> header & JB_CMASK ;
26712733 /* Since this is an object, account for *Pairs* of Jentrys */
26722734 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 ;
26762738 uint32 stopLow = 0 ,
26772739 stopHigh = count ;
26782740
@@ -2682,6 +2744,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26822744 if (count <= 0 )
26832745 return NULL ;
26842746
2747+ base_addr = initKVMap (& kvmap , base_addr , count , sorted_values );
2748+ base_offset = base_addr - (char * ) jb ;
2749+
26852750 key .type = jbvString ;
26862751 key .val .string .val = keystr ;
26872752 key .val .string .len = keylen ;
@@ -2713,7 +2778,7 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
27132778 if (difference == 0 )
27142779 {
27152780 /* Found our key, return corresponding value */
2716- int index = ( sorted_values ? kvmap [ stopMiddle ] : stopMiddle ) + count ;
2781+ int index = JSONB_KVMAP_ENTRY ( & kvmap , stopMiddle ) + count ;
27172782
27182783 return fillCompressedJsonbValue (cjb , container , index , base_addr ,
27192784 getJsonbOffset (container , index ),
0 commit comments