diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 29f058c..eca1684 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -57,6 +57,7 @@
 #include "utils/memutils.h"
 #include "utils/typcache.h"
 #include "utils/xml.h"
+#include "utils/jsonb.h"
 
 
 /* static function decls */
@@ -272,6 +273,7 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 	IntArray	upper,
 				lower;
 	int		   *lIndex;
+	text	   **path;
 
 	array_source = ExecEvalExpr(astate->refexpr,
 								econtext,
@@ -290,6 +292,11 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 			return (Datum) NULL;
 	}
 
+	if (arrayRef->refarraytype == JSONBOID)
+	{
+		path = (text **) palloc(astate->refupperindexpr->length * sizeof(text*));
+	}
+
 	foreach(l, astate->refupperindexpr)
 	{
 		ExprState  *eltstate = (ExprState *) lfirst(l);
@@ -300,10 +307,21 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 					 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
 							i + 1, MAXDIM)));
 
-		upper.indx[i++] = DatumGetInt32(ExecEvalExpr(eltstate,
-													 econtext,
-													 &eisnull,
-													 NULL));
+		if (arrayRef->refarraytype == JSONBOID)
+		{
+			path[i++] = cstring_to_text((char *)DatumGetPointer(ExecEvalExpr(eltstate,
+						econtext,
+						&eisnull,
+						NULL)));
+		}
+		else
+		{
+			upper.indx[i++] = DatumGetInt32(ExecEvalExpr(eltstate,
+						econtext,
+						&eisnull,
+						NULL));
+		}
+
 		/* If any index expr yields NULL, result is NULL or error */
 		if (eisnull)
 		{
@@ -445,14 +463,24 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 		}
 
 		if (lIndex == NULL)
-			return array_set_element(array_source, i,
-									 upper.indx,
-									 sourceData,
-									 eisnull,
-									 astate->refattrlength,
-									 astate->refelemlength,
-									 astate->refelembyval,
-									 astate->refelemalign);
+		{
+			if (arrayRef->refarraytype == JSONBOID && path != NULL)
+			{
+				return jsonb_set_element(array_source, path, i, sourceData,
+						((const ArrayRef *) astate->xprstate.expr)->refelemtype);
+			}
+			else
+			{
+				return array_set_element(array_source, i,
+						upper.indx,
+						sourceData,
+						eisnull,
+						astate->refattrlength,
+						astate->refelemlength,
+						astate->refelembyval,
+						astate->refelemalign);
+			}
+		}
 		else
 			return array_set_slice(array_source, i,
 								   upper.indx, lower.indx,
@@ -465,13 +493,22 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
 	}
 
 	if (lIndex == NULL)
-		return array_get_element(array_source, i,
-								 upper.indx,
-								 astate->refattrlength,
-								 astate->refelemlength,
-								 astate->refelembyval,
-								 astate->refelemalign,
-								 isNull);
+	{
+		if (arrayRef->refarraytype == JSONBOID && path != NULL)
+		{
+			return jsonb_get_element(array_source, path, i, isNull);
+		}
+		else
+		{
+			return array_get_element(array_source, i,
+					upper.indx,
+					astate->refattrlength,
+					astate->refelemlength,
+					astate->refelembyval,
+					astate->refelemalign,
+					isNull);
+		}
+	}
 	else
 		return array_get_slice(array_source, i,
 							   upper.indx, lower.indx,
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index fa77ef1..a08eaab 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -470,13 +470,29 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection)
 	}
 	/* process trailing subscripts, if any */
 	if (subscripts)
-		result = (Node *) transformArraySubscripts(pstate,
-												   result,
-												   exprType(result),
-												   InvalidOid,
-												   exprTypmod(result),
-												   subscripts,
-												   NULL);
+	{
+		if (exprType(result) == JSONBOID)
+		{
+			result = (Node *) transformJsonbSubscripts(pstate,
+					result,
+					exprType(result),
+					JSONBOID,
+					exprTypmod(result),
+					subscripts,
+					NULL);
+		}
+		else
+		{
+			result = (Node *) transformArraySubscripts(pstate,
+					result,
+					exprType(result),
+					InvalidOid,
+					exprTypmod(result),
+					subscripts,
+					NULL);
+		}
+
+	}
 
 	return result;
 }
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 4130cbf..3433532 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -258,6 +258,51 @@ transformArrayType(Oid *arrayType, int32 *arrayTypmod)
 	return elementType;
 }
 
+ArrayRef *
+transformJsonbSubscripts(ParseState *pstate,
+						 Node *arrayBase,
+						 Oid arrayType,
+						 Oid elementType,
+						 int32 arrayTypMod,
+						 List *indirection,
+						 Node *assignFrom)
+{
+	List	   *upperIndexpr = NIL;
+	List	   *lowerIndexpr = NIL;
+	ListCell   *idx;
+	ArrayRef   *aref;
+
+	/*
+	 * Transform the subscript expressions.
+	 */
+	foreach(idx, indirection)
+	{
+		A_Indices  *ai = (A_Indices *) lfirst(idx);
+		Node	   *subexpr;
+
+		Assert(IsA(ai, A_Indices));
+		subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
+		upperIndexpr = lappend(upperIndexpr, subexpr);
+	}
+
+	/*
+	 * Ready to build the ArrayRef node.
+	 */
+	aref = makeNode(ArrayRef);
+	aref->refarraytype = arrayType;
+	aref->refelemtype = elementType;
+	aref->reftypmod = arrayTypMod;
+	/* refcollid will be set by parse_collate.c */
+	aref->refupperindexpr = upperIndexpr;
+	aref->reflowerindexpr = lowerIndexpr;
+	aref->refexpr = (Expr *) arrayBase;
+	aref->refassgnexpr = (Expr *) assignFrom;
+
+	return aref;
+}
+
+
+
 /*
  * transformArraySubscripts()
  *		Transform array subscripting.  This is used for both
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 1b3fcd6..5f72a66 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -45,6 +45,19 @@ static Node *transformAssignmentIndirection(ParseState *pstate,
 							   ListCell *indirection,
 							   Node *rhs,
 							   int location);
+
+static Node *transformJsonbAssignmentSubscripts(ParseState *pstate,
+							  Node *basenode,
+							  const char *targetName,
+							  Oid targetTypeId,
+							  int32 targetTypMod,
+							  Oid targetCollation,
+							  List *subscripts,
+							  bool isSlice,
+							  ListCell *next_indirection,
+							  Node *rhs,
+							  int location);
+
 static Node *transformAssignmentSubscripts(ParseState *pstate,
 							  Node *basenode,
 							  const char *targetName,
@@ -744,27 +757,52 @@ transformAssignmentIndirection(ParseState *pstate,
 	if (subscripts)
 	{
 		/* recurse, and then return because we're done */
-		return transformAssignmentSubscripts(pstate,
-											 basenode,
-											 targetName,
-											 targetTypeId,
-											 targetTypMod,
-											 targetCollation,
-											 subscripts,
-											 isSlice,
-											 NULL,
-											 rhs,
-											 location);
+		if (exprType(basenode) == JSONBOID)
+		{
+			return transformJsonbAssignmentSubscripts(pstate,
+					basenode,
+					targetName,
+					targetTypeId,
+					targetTypMod,
+					targetCollation,
+					subscripts,
+					isSlice,
+					i,
+					rhs,
+					location);
+		}
+		else
+		{
+			return transformAssignmentSubscripts(pstate,
+					basenode,
+					targetName,
+					targetTypeId,
+					targetTypMod,
+					targetCollation,
+					subscripts,
+					isSlice,
+					NULL,
+					rhs,
+					location);
+		}
 	}
 
 	/* base case: just coerce RHS to match target type ID */
 
-	result = coerce_to_target_type(pstate,
-								   rhs, exprType(rhs),
-								   targetTypeId, targetTypMod,
-								   COERCION_ASSIGNMENT,
-								   COERCE_IMPLICIT_CAST,
-								   -1);
+	if (targetTypeId != InvalidOid)
+	{
+		result = coerce_to_target_type(pstate,
+									   rhs, exprType(rhs),
+									   targetTypeId, targetTypMod,
+									   COERCION_ASSIGNMENT,
+									   COERCE_IMPLICIT_CAST,
+									   -1);
+	}
+	else
+	{
+		result = rhs;
+	}
+
 	if (result == NULL)
 	{
 		if (targetIsArray)
@@ -792,6 +830,92 @@ transformAssignmentIndirection(ParseState *pstate,
 	return result;
 }
 
+static Node *
+transformJsonbAssignmentSubscripts(ParseState *pstate,
+							  Node *basenode,
+							  const char *targetName,
+							  Oid targetTypeId,
+							  int32 targetTypMod,
+							  Oid targetCollation,
+							  List *subscripts,
+							  bool isSlice,
+							  ListCell *next_indirection,
+							  Node *rhs,
+							  int location)
+{
+	Node	   *result;
+	Oid			arrayType;
+	int32		arrayTypMod;
+	Oid			elementTypeId;
+	Oid			typeNeeded;
+	Oid			collationNeeded;
+
+	Assert(subscripts != NIL);
+
+	/* Identify the actual array type and element type involved */
+	arrayType = targetTypeId;
+	arrayTypMod = targetTypMod;
+	elementTypeId = InvalidOid;
+
+	/* Identify type that RHS must provide */
+	typeNeeded = isSlice ? arrayType : elementTypeId;
+
+	/*
+	 * Array normally has same collation as elements, but there's an
+	 * exception: we might be subscripting a domain over an array type. In
+	 * that case use collation of the base type.
+	 */
+	if (arrayType == targetTypeId)
+		collationNeeded = targetCollation;
+	else
+		collationNeeded = get_typcollation(arrayType);
+
+	/* recurse to create appropriate RHS for array assign */
+	rhs = transformAssignmentIndirection(pstate,
+										 NULL,
+										 targetName,
+										 true,
+										 typeNeeded,
+										 arrayTypMod,
+										 collationNeeded,
+										 next_indirection,
+										 rhs,
+										 location);
+
+	/* process subscripts */
+	result = (Node *) transformJsonbSubscripts(pstate,
+											   basenode,
+											   arrayType,
+											   exprType(rhs),
+											   arrayTypMod,
+											   subscripts,
+											   rhs);
+
+	/* If target was a domain over array, need to coerce up to the domain */
+	if (arrayType != targetTypeId)
+	{
+		Oid			resulttype = exprType(result);
+
+		result = coerce_to_target_type(pstate,
+									   result, resulttype,
+									   targetTypeId, targetTypMod,
+									   COERCION_ASSIGNMENT,
+									   COERCE_IMPLICIT_CAST,
+									   -1);
+		/* can fail if we had int2vector/oidvector, but not for true domains */
+		if (result == NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_CANNOT_COERCE),
+					 errmsg("cannot cast type %s to %s",
+							format_type_be(resulttype),
+							format_type_be(targetTypeId)),
+					 parser_errposition(pstate, location)));
+	}
+
+	return result;
+}
+
+
 /*
  * helper for transformAssignmentIndirection: process array assignment
  */
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c
index 154bc36..523a0ca 100644
--- a/src/backend/utils/adt/jsonb.c
+++ b/src/backend/utils/adt/jsonb.c
@@ -1943,3 +1943,45 @@ jsonb_object_agg_finalfn(PG_FUNCTION_ARGS)
 
 	PG_RETURN_POINTER(out);
 }
+
+
+Datum
+jsonb_set_element(Datum jsonbdatum,
+		text **path, int path_len, Datum sourceData, Oid source_type)
+{
+	Jsonb				*jb = DatumGetJsonb(jsonbdatum);
+	JsonbInState		result;
+	JsonbTypeCategory	tcategory;
+	Oid					outfuncoid;
+	JsonbValue			v, newkey, newval;
+	JsonbParseState 	*state = NULL;
+	JsonbIterator 		*it;
+	uint32 				r;
+	JsonbValue 			*res = NULL;
+	int					i, level = 0;
+	bool				*path_nulls = palloc(path_len * sizeof(bool));
+
+	jsonb_categorize_type(source_type,
+						  &tcategory, &outfuncoid);
+	memset(&result, 0, sizeof(JsonbInState));
+	result.parseState = NULL;
+	datum_to_jsonb(sourceData, false, &result, tcategory, outfuncoid, false);
+
+	it = JsonbIteratorInit(&jb->root);
+
+	newval = *result.res;
+
+	if (newval.type == jbvArray && newval.val.array.rawScalar == true)
+	{
+		newval = newval.val.array.elems[0];
+	}
+
+	for(i = 0; i < path_len; i++)
+	{
+		path_nulls[i]= false;
+	}
+
+	res = setPath(&it, path, path_nulls, path_len, &state, 0, (void *)&newval, true, true);
+
+	PG_RETURN_JSONB(JsonbValueToJsonb(res));
+}
diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c
index 4d73315..aa2384b 100644
--- a/src/backend/utils/adt/jsonb_util.c
+++ b/src/backend/utils/adt/jsonb_util.c
@@ -408,7 +408,6 @@ findJsonbValueFromContainer(JsonbContainer *container, uint32 flags,
 	pfree(result);
 	return NULL;
 }
-
 /*
  * Get i-th value of a Jsonb array.
  *
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index 3b8d42e..1b4074e 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -33,6 +33,12 @@
 #include "utils/memutils.h"
 #include "utils/typcache.h"
 
+#define add_newval(state, newval, unpacked) \
+	if (unpacked) \
+		(void) pushJsonbValue(st, WJB_VALUE, (JsonbValue *)newval); \
+	else  \
+		addJsonbToParseState(st, (Jsonb *)newval);
+
 /* semantic action functions for json_object_keys */
 static void okeys_object_field_start(void *state, char *fname, bool isnull);
 static void okeys_array_start(void *state);
@@ -127,17 +133,13 @@ static JsonbValue *findJsonbValueFromContainerLen(JsonbContainer *container,
 /* functions supporting jsonb_delete, jsonb_set and jsonb_concat */
 static JsonbValue *IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
 			   JsonbParseState **state);
-static JsonbValue *setPath(JsonbIterator **it, Datum *path_elems,
-		bool *path_nulls, int path_len,
-		JsonbParseState **st, int level, Jsonb *newval,
-		bool create);
 static void setPathObject(JsonbIterator **it, Datum *path_elems,
 			  bool *path_nulls, int path_len, JsonbParseState **st,
 			  int level,
-			  Jsonb *newval, uint32 npairs, bool create);
+			  void *newval, bool unpacked, uint32 npairs, bool create);
 static void setPathArray(JsonbIterator **it, Datum *path_elems,
 			 bool *path_nulls, int path_len, JsonbParseState **st,
-			 int level, Jsonb *newval, uint32 nelems, bool create);
+			 int level, void *newval, bool unpacked, uint32 nelems, bool create);
 static void addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb);
 
 /* state for json_object_keys */
@@ -3538,7 +3540,7 @@ jsonb_set(PG_FUNCTION_ARGS)
 	it = JsonbIteratorInit(&in->root);
 
 	res = setPath(&it, path_elems, path_nulls, path_len, &st,
-				  0, newval, create);
+				  0, (void *)newval, false, create);
 
 	Assert(res != NULL);
 
@@ -3582,7 +3584,7 @@ jsonb_delete_path(PG_FUNCTION_ARGS)
 
 	it = JsonbIteratorInit(&in->root);
 
-	res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, NULL, false);
+	res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, NULL, false, false);
 
 	Assert(res != NULL);
 
@@ -3709,10 +3711,10 @@ IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
  * does not exist. All path elements before the last must already exist
  * whether or not create is true, or nothing is done.
  */
-static JsonbValue *
+JsonbValue *
 setPath(JsonbIterator **it, Datum *path_elems,
 		bool *path_nulls, int path_len,
-		JsonbParseState **st, int level, Jsonb *newval, bool create)
+		JsonbParseState **st, int level, void *newval, bool unpacked, bool create)
 {
 	JsonbValue	v;
 	JsonbValue *res = NULL;
@@ -3725,7 +3727,7 @@ setPath(JsonbIterator **it, Datum *path_elems,
 		case WJB_BEGIN_ARRAY:
 			(void) pushJsonbValue(st, r, NULL);
 			setPathArray(it, path_elems, path_nulls, path_len, st, level,
-						 newval, v.val.array.nElems, create);
+						 newval, unpacked, v.val.array.nElems, create);
 			r = JsonbIteratorNext(it, &v, false);
 			Assert(r == WJB_END_ARRAY);
 			res = pushJsonbValue(st, r, NULL);
@@ -3734,7 +3736,7 @@ setPath(JsonbIterator **it, Datum *path_elems,
 		case WJB_BEGIN_OBJECT:
 			(void) pushJsonbValue(st, r, NULL);
 			setPathObject(it, path_elems, path_nulls, path_len, st, level,
-						  newval, v.val.object.nPairs, create);
+						  newval, unpacked, v.val.object.nPairs, create);
 			r = JsonbIteratorNext(it, &v, true);
 			Assert(r == WJB_END_OBJECT);
 			res = pushJsonbValue(st, r, NULL);
@@ -3757,7 +3759,7 @@ setPath(JsonbIterator **it, Datum *path_elems,
 static void
 setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
 			  int path_len, JsonbParseState **st, int level,
-			  Jsonb *newval, uint32 npairs, bool create)
+			  void *newval, bool unpacked, uint32 npairs, bool create)
 {
 	JsonbValue	v;
 	int			i;
@@ -3767,17 +3769,34 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
 	if (level >= path_len || path_nulls[level])
 		done = true;
 
-	/* empty object is a special case for create */
-	if ((npairs == 0) && create && (level == path_len - 1))
+	if ((npairs == 0) && create)
 	{
+		int		i;
+		for (i = 0; i < path_len - 1 - level; i++)
+		{
+			JsonbValue	newkey;
+
+			newkey.type = jbvString;
+			newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[level + i]);
+			newkey.val.string.val = VARDATA_ANY(path_elems[level + i]);
+
+			(void) pushJsonbValue(st, WJB_KEY, &newkey);
+			(void) pushJsonbValue(st, WJB_BEGIN_OBJECT, NULL);
+		}
+
 		JsonbValue	newkey;
 
 		newkey.type = jbvString;
-		newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[level]);
-		newkey.val.string.val = VARDATA_ANY(path_elems[level]);
+		newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[level + i]);
+		newkey.val.string.val = VARDATA_ANY(path_elems[level + i]);
 
 		(void) pushJsonbValue(st, WJB_KEY, &newkey);
-		addJsonbToParseState(st, newval);
+		add_newval(st, newval, unpacked);
+
+		for (i = 0; i < path_len - 1 - level; i++)
+		{
+			(void) pushJsonbValue(st, WJB_END_OBJECT, NULL);
+		}
 	}
 
 	for (i = 0; i < npairs; i++)
@@ -3797,7 +3816,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
 				if (newval != NULL)
 				{
 					(void) pushJsonbValue(st, WJB_KEY, &k);
-					addJsonbToParseState(st, newval);
+					add_newval(st, newval, unpacked);
 				}
 				done = true;
 			}
@@ -3805,7 +3824,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
 			{
 				(void) pushJsonbValue(st, r, &k);
 				setPath(it, path_elems, path_nulls, path_len,
-						st, level + 1, newval, create);
+						st, level + 1, newval, unpacked, create);
 			}
 		}
 		else
@@ -3819,7 +3838,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
 				newkey.val.string.val = VARDATA_ANY(path_elems[level]);
 
 				(void) pushJsonbValue(st, WJB_KEY, &newkey);
-				addJsonbToParseState(st, newval);
+				add_newval(st, newval, unpacked);
 			}
 
 			(void) pushJsonbValue(st, r, &k);
@@ -3851,7 +3870,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
 static void
 setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
 			 int path_len, JsonbParseState **st, int level,
-			 Jsonb *newval, uint32 nelems, bool create)
+			 void *newval, bool unpacked, uint32 nelems, bool create)
 {
 	JsonbValue	v;
 	int			idx,
@@ -3896,7 +3915,7 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
 	if ((idx == INT_MIN || nelems == 0) && create && (level == path_len - 1))
 	{
 		Assert(newval != NULL);
-		addJsonbToParseState(st, newval);
+		add_newval(st, newval, unpacked);
 		done = true;
 	}
 
@@ -3911,13 +3930,13 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
 			{
 				r = JsonbIteratorNext(it, &v, true);	/* skip */
 				if (newval != NULL)
-					addJsonbToParseState(st, newval);
+					add_newval(st, newval, unpacked);
 
 				done = true;
 			}
 			else
 				(void) setPath(it, path_elems, path_nulls, path_len,
-							   st, level + 1, newval, create);
+							   st, level + 1, newval, unpacked, create);
 		}
 		else
 		{
@@ -3944,9 +3963,46 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
 
 			if (create && !done && level == path_len - 1 && i == nelems - 1)
 			{
-				addJsonbToParseState(st, newval);
+				add_newval(st, newval, unpacked);
 			}
 
 		}
 	}
 }
+
+
+Datum
+jsonb_get_element(Datum jsonbdatum,
+		text **path, int path_len, bool *isNull)
+{
+	Jsonb	   *jb = DatumGetJsonb(jsonbdatum);
+	JsonbValue *v;
+	int			level = 1;
+
+	if (!JB_ROOT_IS_OBJECT(jb))
+	{
+		*isNull = true;
+		return (Datum) 0;
+	}
+
+	v = findJsonbValueFromContainerLen(&jb->root, JB_FOBJECT,
+									   VARDATA_ANY(path[0]),
+									   VARSIZE_ANY_EXHDR(path[0]));
+
+	while (v != NULL &&
+		   v->type == jbvBinary && level < path_len)
+	{
+		v = findJsonbValueFromContainerLen(v->val.binary.data, JB_FOBJECT,
+									       VARDATA_ANY(path[level]),
+									       VARSIZE_ANY_EXHDR(path[level]));
+		level++;
+	}
+
+	if (v != NULL && level == path_len)
+	{
+		PG_RETURN_JSONB(JsonbValueToJsonb(v));
+	}
+
+	*isNull = true;
+	return (Datum) 0;
+}
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 5249945..8c50e2b 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -224,6 +224,13 @@ extern void cancel_parser_errposition_callback(ParseCallbackState *pcbstate);
 extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno,
 		 int location);
 extern Oid	transformArrayType(Oid *arrayType, int32 *arrayTypmod);
+extern ArrayRef *transformJsonbSubscripts(ParseState *pstate,
+						 Node *arrayBase,
+						 Oid arrayType,
+						 Oid elementType,
+						 int32 arrayTypMod,
+						 List *indirection,
+						 Node *assignFrom);
 extern ArrayRef *transformArraySubscripts(ParseState *pstate,
 						 Node *arrayBase,
 						 Oid arrayType,
diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h
index 3049a87..124b6b4 100644
--- a/src/include/utils/jsonb.h
+++ b/src/include/utils/jsonb.h
@@ -433,5 +433,11 @@ extern char *JsonbToCString(StringInfo out, JsonbContainer *in,
 extern char *JsonbToCStringIndent(StringInfo out, JsonbContainer *in,
 					 int estimated_len);
 
+extern Datum jsonb_set_element(Datum datum, text **path, int path_len, Datum sourceData, Oid source_type);
+extern Datum jsonb_get_element(Datum datum, text **path, int path_len, bool *isNull);
+extern JsonbValue *setPath(JsonbIterator **it, Datum *path_elems,
+		bool *path_nulls, int path_len,
+		JsonbParseState **st, int level, void *newval,
+		bool unpacked, bool create);
 
 #endif   /* __JSONB_H__ */
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
index 17656d4..915f97b 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -3295,3 +3295,97 @@ select jsonb_set('[]','{-99}','{"foo":123}');
  [{"foo": 123}]
 (1 row)
 
+-- jsonb subscript
+select ('{"a": 1}'::jsonb)['a'];
+ jsonb 
+-------
+ 1
+(1 row)
+
+select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['b'];
+ jsonb 
+-------
+ "c"
+(1 row)
+
+select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d'];
+   jsonb   
+-----------
+ [1, 2, 3]
+(1 row)
+
+select ('{"a": 1}'::jsonb)['not_exist'];
+ jsonb 
+-------
+ 
+(1 row)
+
+select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1'];
+     jsonb     
+---------------
+ {"a2": "aaa"}
+(1 row)
+
+select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']['a2'];
+ jsonb 
+-------
+ "aaa"
+(1 row)
+
+select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']['a2']['a3'];
+ jsonb 
+-------
+ 
+(1 row)
+
+create TEMP TABLE test_jsonb_subscript (
+       id int,
+       test_json jsonb
+);
+insert into test_jsonb_subscript values
+(1, '{}'),
+(2, '{}');
+update test_jsonb_subscript set test_json['a'] = 1;
+select * from test_jsonb_subscript;
+ id | test_json 
+----+-----------
+  1 | {"a": 1}
+  2 | {"a": 1}
+(2 rows)
+
+update test_jsonb_subscript set test_json['a'] = 'test';
+select * from test_jsonb_subscript;
+ id |   test_json   
+----+---------------
+  1 | {"a": "test"}
+  2 | {"a": "test"}
+(2 rows)
+
+update test_jsonb_subscript set test_json['a'] = '{"b": 1}'::jsonb;
+select * from test_jsonb_subscript;
+ id |    test_json    
+----+-----------------
+  1 | {"a": {"b": 1}}
+  2 | {"a": {"b": 1}}
+(2 rows)
+
+update test_jsonb_subscript set test_json['a'] = '[1, 2, 3]'::jsonb;
+select * from test_jsonb_subscript;
+ id |    test_json     
+----+------------------
+  1 | {"a": [1, 2, 3]}
+  2 | {"a": [1, 2, 3]}
+(2 rows)
+
+delete from test_jsonb_subscript;
+insert into test_jsonb_subscript values
+(1, '{}'),
+(2, '{}');
+update test_jsonb_subscript set test_json['b']['b1']['b2'] = 1;
+select * from test_jsonb_subscript;
+ id |        test_json         
+----+--------------------------
+  1 | {"b": {"b1": {"b2": 1}}}
+  2 | {"b": {"b1": {"b2": 1}}}
+(2 rows)
+
diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql
index 83ed4eb..d7e3aa7 100644
--- a/src/test/regress/sql/jsonb.sql
+++ b/src/test/regress/sql/jsonb.sql
@@ -809,3 +809,41 @@ select jsonb_set('{}','{x}','{"foo":123}');
 select jsonb_set('[]','{0}','{"foo":123}');
 select jsonb_set('[]','{99}','{"foo":123}');
 select jsonb_set('[]','{-99}','{"foo":123}');
+
+-- jsonb subscript
+select ('{"a": 1}'::jsonb)['a'];
+select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['b'];
+select ('{"a": 1, "b": "c", "d": [1, 2, 3]}'::jsonb)['d'];
+select ('{"a": 1}'::jsonb)['not_exist'];
+select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1'];
+select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']['a2'];
+select ('{"a": {"a1": {"a2": "aaa"}}, "b": "bbb", "c": "ccc"}'::jsonb)['a']['a1']['a2']['a3'];
+
+create TEMP TABLE test_jsonb_subscript (
+       id int,
+       test_json jsonb
+);
+
+insert into test_jsonb_subscript values
+(1, '{}'),
+(2, '{}');
+
+update test_jsonb_subscript set test_json['a'] = 1;
+select * from test_jsonb_subscript;
+
+update test_jsonb_subscript set test_json['a'] = 'test';
+select * from test_jsonb_subscript;
+
+update test_jsonb_subscript set test_json['a'] = '{"b": 1}'::jsonb;
+select * from test_jsonb_subscript;
+
+update test_jsonb_subscript set test_json['a'] = '[1, 2, 3]'::jsonb;
+select * from test_jsonb_subscript;
+
+delete from test_jsonb_subscript;
+insert into test_jsonb_subscript values
+(1, '{}'),
+(2, '{}');
+
+update test_jsonb_subscript set test_json['b']['b1']['b2'] = 1;
+select * from test_jsonb_subscript;
