diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c
index e47eaea..4e7fe67 100644
*** a/src/backend/utils/adt/jsonb_util.c
--- b/src/backend/utils/adt/jsonb_util.c
***************
*** 26,33 ****
   * in MaxAllocSize, and the number of elements (or pairs) must fit in the bits
   * reserved for that in the JsonbContainer.header field.
   *
!  * (the total size of an array's elements is also limited by JENTRY_LENMASK,
!  * but we're not concerned about that here)
   */
  #define JSONB_MAX_ELEMS (Min(MaxAllocSize / sizeof(JsonbValue), JB_CMASK))
  #define JSONB_MAX_PAIRS (Min(MaxAllocSize / sizeof(JsonbPair), JB_CMASK))
--- 26,33 ----
   * in MaxAllocSize, and the number of elements (or pairs) must fit in the bits
   * reserved for that in the JsonbContainer.header field.
   *
!  * (The total size of an array's or object's elements is also limited by
!  * JENTRY_LENMASK, but we're not concerned about that here.)
   */
  #define JSONB_MAX_ELEMS (Min(MaxAllocSize / sizeof(JsonbValue), JB_CMASK))
  #define JSONB_MAX_PAIRS (Min(MaxAllocSize / sizeof(JsonbPair), JB_CMASK))
*************** findJsonbValueFromContainer(JsonbContain
*** 294,303 ****
  {
  	JEntry	   *children = container->children;
  	int			count = (container->header & JB_CMASK);
! 	JsonbValue *result = palloc(sizeof(JsonbValue));
  
  	Assert((flags & ~(JB_FARRAY | JB_FOBJECT)) == 0);
  
  	if (flags & JB_FARRAY & container->header)
  	{
  		char	   *base_addr = (char *) (children + count);
--- 294,309 ----
  {
  	JEntry	   *children = container->children;
  	int			count = (container->header & JB_CMASK);
! 	JsonbValue *result;
  
  	Assert((flags & ~(JB_FARRAY | JB_FOBJECT)) == 0);
  
+ 	/* Quick out without a palloc cycle if object/array is empty */
+ 	if (count <= 0)
+ 		return NULL;
+ 
+ 	result = palloc(sizeof(JsonbValue));
+ 
  	if (flags & JB_FARRAY & container->header)
  	{
  		char	   *base_addr = (char *) (children + count);
*************** findJsonbValueFromContainer(JsonbContain
*** 323,329 ****
  		char	   *base_addr = (char *) (children + count * 2);
  		uint32	   *offsets;
  		uint32		lastoff;
! 		int			lastoffpos;
  		uint32		stopLow = 0,
  					stopHigh = count;
  
--- 329,335 ----
  		char	   *base_addr = (char *) (children + count * 2);
  		uint32	   *offsets;
  		uint32		lastoff;
! 		int			i;
  		uint32		stopLow = 0,
  					stopHigh = count;
  
*************** findJsonbValueFromContainer(JsonbContain
*** 332,379 ****
  
  		/*
  		 * We use a cache to avoid redundant getJsonbOffset() computations
! 		 * inside the search loop.  Note that count may well be zero at this
! 		 * point; to avoid an ugly special case for initializing lastoff and
! 		 * lastoffpos, we allocate one extra array element.
  		 */
! 		offsets = (uint32 *) palloc((count * 2 + 1) * sizeof(uint32));
! 		offsets[0] = lastoff = 0;
! 		lastoffpos = 0;
  
  		/* Binary search on object/pair keys *only* */
  		while (stopLow < stopHigh)
  		{
  			uint32		stopMiddle;
- 			int			index;
  			int			difference;
  			JsonbValue	candidate;
  
  			stopMiddle = stopLow + (stopHigh - stopLow) / 2;
  
- 			/*
- 			 * Compensate for the fact that we're searching through pairs (not
- 			 * entries).
- 			 */
- 			index = stopMiddle * 2;
- 
- 			/* Update the offsets cache through at least index+1 */
- 			while (lastoffpos <= index)
- 			{
- 				lastoff += JBE_LEN(children, lastoffpos);
- 				offsets[++lastoffpos] = lastoff;
- 			}
- 
  			candidate.type = jbvString;
! 			candidate.val.string.val = base_addr + offsets[index];
! 			candidate.val.string.len = JBE_LEN(children, index);
  
  			difference = lengthCompareJsonbStringValue(&candidate, key);
  
  			if (difference == 0)
  			{
! 				/* Found our key, return value */
! 				fillJsonbValue(children, index + 1,
! 							   base_addr, offsets[index + 1],
  							   result);
  
  				pfree(offsets);
--- 338,383 ----
  
  		/*
  		 * We use a cache to avoid redundant getJsonbOffset() computations
! 		 * inside the search loop.  The entire cache can be filled immediately
! 		 * since we expect to need the last offset for value access.  (This
! 		 * choice could lose if the key is not present, but avoiding extra
! 		 * logic inside the search loop probably makes up for that.)
  		 */
! 		offsets = (uint32 *) palloc(count * sizeof(uint32));
! 		lastoff = 0;
! 		for (i = 0; i < count; i++)
! 		{
! 			offsets[i] = lastoff;
! 			lastoff += JBE_LEN(children, i);
! 		}
! 		/* lastoff now has the offset of the first value item */
  
  		/* Binary search on object/pair keys *only* */
  		while (stopLow < stopHigh)
  		{
  			uint32		stopMiddle;
  			int			difference;
  			JsonbValue	candidate;
  
  			stopMiddle = stopLow + (stopHigh - stopLow) / 2;
  
  			candidate.type = jbvString;
! 			candidate.val.string.val = base_addr + offsets[stopMiddle];
! 			candidate.val.string.len = JBE_LEN(children, stopMiddle);
  
  			difference = lengthCompareJsonbStringValue(&candidate, key);
  
  			if (difference == 0)
  			{
! 				/* Found our key, return corresponding value */
! 				int			index = stopMiddle + count;
! 
! 				/* navigate to appropriate offset */
! 				for (i = count; i < index; i++)
! 					lastoff += JBE_LEN(children, i);
! 
! 				fillJsonbValue(children, index,
! 							   base_addr, lastoff,
  							   result);
  
  				pfree(offsets);
*************** recurse:
*** 730,735 ****
--- 734,740 ----
  			val->val.array.rawScalar = (*it)->isScalar;
  			(*it)->curIndex = 0;
  			(*it)->curDataOffset = 0;
+ 			(*it)->curValueOffset = 0;	/* not actually used */
  			/* Set state for next call */
  			(*it)->state = JBI_ARRAY_ELEM;
  			return WJB_BEGIN_ARRAY;
*************** recurse:
*** 780,785 ****
--- 785,792 ----
  			 */
  			(*it)->curIndex = 0;
  			(*it)->curDataOffset = 0;
+ 			(*it)->curValueOffset = getJsonbOffset((*it)->children,
+ 												   (*it)->nElems);
  			/* Set state for next call */
  			(*it)->state = JBI_OBJECT_KEY;
  			return WJB_BEGIN_OBJECT;
*************** recurse:
*** 799,805 ****
  			else
  			{
  				/* Return key of a key/value pair.  */
! 				fillJsonbValue((*it)->children, (*it)->curIndex * 2,
  							   (*it)->dataProper, (*it)->curDataOffset,
  							   val);
  				if (val->type != jbvString)
--- 806,812 ----
  			else
  			{
  				/* Return key of a key/value pair.  */
! 				fillJsonbValue((*it)->children, (*it)->curIndex,
  							   (*it)->dataProper, (*it)->curDataOffset,
  							   val);
  				if (val->type != jbvString)
*************** recurse:
*** 814,828 ****
  			/* Set state for next call */
  			(*it)->state = JBI_OBJECT_KEY;
  
! 			(*it)->curDataOffset += JBE_LEN((*it)->children,
! 											(*it)->curIndex * 2);
! 
! 			fillJsonbValue((*it)->children, (*it)->curIndex * 2 + 1,
! 						   (*it)->dataProper, (*it)->curDataOffset,
  						   val);
  
  			(*it)->curDataOffset += JBE_LEN((*it)->children,
! 											(*it)->curIndex * 2 + 1);
  			(*it)->curIndex++;
  
  			/*
--- 821,834 ----
  			/* Set state for next call */
  			(*it)->state = JBI_OBJECT_KEY;
  
! 			fillJsonbValue((*it)->children, (*it)->curIndex + (*it)->nElems,
! 						   (*it)->dataProper, (*it)->curValueOffset,
  						   val);
  
  			(*it)->curDataOffset += JBE_LEN((*it)->children,
! 											(*it)->curIndex);
! 			(*it)->curValueOffset += JBE_LEN((*it)->children,
! 											 (*it)->curIndex + (*it)->nElems);
  			(*it)->curIndex++;
  
  			/*
*************** convertJsonbObject(StringInfo buffer, JE
*** 1509,1514 ****
--- 1515,1524 ----
  	/* Reserve space for the JEntries of the keys and values. */
  	metaoffset = reserveFromBuffer(buffer, sizeof(JEntry) * val->val.object.nPairs * 2);
  
+ 	/*
+ 	 * Iterate over the keys, then over the values, since that is the ordering
+ 	 * we want in the on-disk representation.
+ 	 */
  	totallen = 0;
  	for (i = 0; i < val->val.object.nPairs; i++)
  	{
*************** convertJsonbObject(StringInfo buffer, JE
*** 1529,1534 ****
--- 1539,1561 ----
  		metaoffset += sizeof(JEntry);
  
  		/*
+ 		 * Bail out if total variable-length data exceeds what will fit in a
+ 		 * JEntry length field.  We check this in each iteration, not just
+ 		 * once at the end, to forestall possible integer overflow.
+ 		 */
+ 		if (totallen > JENTRY_LENMASK)
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ 					 errmsg("total size of jsonb object elements exceeds the maximum of %u bytes",
+ 							JENTRY_LENMASK)));
+ 	}
+ 	for (i = 0; i < val->val.object.nPairs; i++)
+ 	{
+ 		JsonbPair  *pair = &val->val.object.pairs[i];
+ 		int			len;
+ 		JEntry		meta;
+ 
+ 		/*
  		 * Convert value, producing a JEntry and appending its variable-length
  		 * data to buffer
  		 */
*************** convertJsonbObject(StringInfo buffer, JE
*** 1543,1551 ****
  		/*
  		 * Bail out if total variable-length data exceeds what will fit in a
  		 * JEntry length field.  We check this in each iteration, not just
! 		 * once at the end, to forestall possible integer overflow.  But it
! 		 * should be sufficient to check once per iteration, since
! 		 * JENTRY_LENMASK is several bits narrower than int.
  		 */
  		if (totallen > JENTRY_LENMASK)
  			ereport(ERROR,
--- 1570,1576 ----
  		/*
  		 * Bail out if total variable-length data exceeds what will fit in a
  		 * JEntry length field.  We check this in each iteration, not just
! 		 * once at the end, to forestall possible integer overflow.
  		 */
  		if (totallen > JENTRY_LENMASK)
  			ereport(ERROR,
diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h
index b9a4314..f9472af 100644
*** a/src/include/utils/jsonb.h
--- b/src/include/utils/jsonb.h
*************** typedef uint32 JEntry;
*** 149,156 ****
  /*
   * A jsonb array or object node, within a Jsonb Datum.
   *
!  * An array has one child for each element. An object has two children for
!  * each key/value pair.
   */
  typedef struct JsonbContainer
  {
--- 149,160 ----
  /*
   * A jsonb array or object node, within a Jsonb Datum.
   *
!  * An array has one child for each element, stored in array order.
!  *
!  * An object has two children for each key/value pair.  The keys all appear
!  * first, in key sort order; then the values appear, in an order matching the
!  * key order.  This arrangement keeps the keys compact in memory, making a
!  * search for a particular key more cache-friendly.
   */
  typedef struct JsonbContainer
  {
*************** typedef struct JsonbContainer
*** 162,169 ****
  } JsonbContainer;
  
  /* flags for the header-field in JsonbContainer */
! #define JB_CMASK				0x0FFFFFFF
! #define JB_FSCALAR				0x10000000
  #define JB_FOBJECT				0x20000000
  #define JB_FARRAY				0x40000000
  
--- 166,173 ----
  } JsonbContainer;
  
  /* flags for the header-field in JsonbContainer */
! #define JB_CMASK				0x0FFFFFFF		/* mask for count field */
! #define JB_FSCALAR				0x10000000		/* flag bits */
  #define JB_FOBJECT				0x20000000
  #define JB_FARRAY				0x40000000
  
*************** struct JsonbValue
*** 238,255 ****
  									 (jsonbval)->type <= jbvBool)
  
  /*
!  * Pair within an Object.
   *
!  * Pairs with duplicate keys are de-duplicated.  We store the order for the
!  * benefit of doing so in a well-defined way with respect to the original
!  * observed order (which is "last observed wins").  This is only used briefly
!  * when originally constructing a Jsonb.
   */
  struct JsonbPair
  {
  	JsonbValue	key;			/* Must be a jbvString */
  	JsonbValue	value;			/* May be of any type */
! 	uint32		order;			/* preserves order of pairs with equal keys */
  };
  
  /* Conversion state used when parsing Jsonb from text, or for type coercion */
--- 242,261 ----
  									 (jsonbval)->type <= jbvBool)
  
  /*
!  * Key/value pair within an Object.
   *
!  * This struct type is only used briefly while constructing a Jsonb; it is
!  * *not* the on-disk representation.
!  *
!  * Pairs with duplicate keys are de-duplicated.  We store the originally
!  * observed pair ordering for the purpose of removing duplicates in a
!  * well-defined way (which is "last observed wins").
   */
  struct JsonbPair
  {
  	JsonbValue	key;			/* Must be a jbvString */
  	JsonbValue	value;			/* May be of any type */
! 	uint32		order;			/* Pair's index in original sequence */
  };
  
  /* Conversion state used when parsing Jsonb from text, or for type coercion */
*************** typedef struct JsonbIterator
*** 284,295 ****
  	/* Data proper.  This points just past end of children array */
  	char	   *dataProper;
  
! 	/* Current item in buffer (up to nElems, but must * 2 for objects) */
  	int			curIndex;
  
  	/* Data offset corresponding to current item */
  	uint32		curDataOffset;
  
  	/* Private state */
  	JsonbIterState state;
  
--- 290,308 ----
  	/* Data proper.  This points just past end of children array */
  	char	   *dataProper;
  
! 	/* Current item in buffer (up to nElems) */
  	int			curIndex;
  
  	/* Data offset corresponding to current item */
  	uint32		curDataOffset;
  
+ 	/*
+ 	 * If the container is an object, we want to return keys and values
+ 	 * alternately; so curDataOffset points to the current key, and
+ 	 * curValueOffset points to the current value.
+ 	 */
+ 	uint32		curValueOffset;
+ 
  	/* Private state */
  	JsonbIterState state;
  
