Commits

Andrew Dunstan committed 4bb12c4

Update to reflect emhancements as committed.

  • Participants
  • Parent commits 226217f

Comments (0)

Files changed (7)

 exists, when rendering a datum of a non-builtin type to json. This means, 
 for example, that a record containing an hstore will have the hstore 
 rendered sanely as a json object rather than as an opaque piece of text.
-* `json_get(json,text, ...)` gives back the value of the named field from a 
-json object
-* `json_get(json, int)` gives back the value of the indicated element from a 
-json array. Elements are counted from 0, unlike SQL arrays.
-* `json_get_text(json, text, ...)` and `json_get_text(json, int)` do the same 
-thing as as the `json_get()` functions, but if the item to be returned is a 
-string it is returned de-escaped and de-quoted.
-* `json_get_path(json, text[])` and 
-`json_get_path_text(json, text[])` return the element at the 
+* certain functions and operators below have text variants. They return the 
+results as text rather than as json, and if the value returned is a json string value, 
+it is dequoted, so you get back `foo"bar` instead of `"foo\"bar"`. The text variants
+also turn join nulls into SQL nulls.
+* note that json arrays are always numbered from 0, unlike the SQL default.
+* operators `->` and `->>` to extract an object key if the right hand operand 
+is a string, or array element if the right hand operand is an integer. `->>` is 
+the text variant as above.
+* operators `#>` and `#>>` take an array of text as the right hand operand, and
+return the corresponding item. `#>>` is the text variant as above.
+* `json_extract_path(json, variadic text[])` and 
+`json_extract_path_text(json, variadic text[])` return the element at the 
 denoted path. Elements in the path can be field names if the element at this 
 nesting level is a json object or textified integers if the item is an array.
-* operators `->` for `json_get()`, `#>` for  `json_get_path()`, `->>` for 
-`json_get_text(`) and `#>>` for `json_get_path_text()`
+`json_extract_path_text()` is the text variant as above.
 * `json_object_keys(json)` returns the set of keys in the json object
 * `json_array_length(json)` returns the length of the json array
-* `json_unnest(json)` returns the elements in the json array. Unlike SQL's 
-`unnest()` only one level of unnesting is done.
-* `json_each(json)` and `json_each_as_text(json)` return the set of key/value 
-pairs in a json object
+* `json_array_elements(json)` returns the elements in the json array. 
+* `json_each(json)` and `json_each_text(json)` return the set of key/value 
+pairs in a json object. `json_each_text()` returns the text variant values 
+as above.
 * `json_populate_record(anyrecord, json, use_json_as_text_bool)` returns the 
 input record with fields with identical names to the fields in a the json 
 object set to the corresponding values. The third boolean parameter defaults
     returns text[]
     language sql
     as
-    $$ select array_agg(j->>$2) from json_unnest($1) j $$;
+    $$ select array_agg(j->>$2) from json_array_elements($1) j $$;
 
     $ create operator | (procedure = json_pluck, leftarg = 'json', rightarg = 'text');
 

File sql/json_enhancements.sql

 -- complain if script is sourced in psql, rather than via CREATE EXTENSION
 \echo Use "CREATE EXTENSION json_enhancements" to load this file. \quit
 
-CREATE FUNCTION json_get(the_json json, element integer)
+CREATE FUNCTION json_array_element(the_json json, element integer)
 RETURNS json
-AS 'MODULE_PATHNAME' , 'json_get_int'
+AS 'MODULE_PATHNAME' , 'json_array_element'
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_get_text(the_json json, element integer)
+CREATE FUNCTION json_array_element_text(the_json json, element integer)
 RETURNS text
-AS 'MODULE_PATHNAME' , 'json_get_text_int'
+AS 'MODULE_PATHNAME' , 'json_array_element_text'
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_get(the_json json, variadic path_elements text[])
+CREATE FUNCTION json_object_field(json, text)
 RETURNS json
-AS 'MODULE_PATHNAME' , 'json_get'
+AS 'MODULE_PATHNAME' , 'json_object_field'
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_get_text(the_json json, variadic path_elements text[])
+CREATE FUNCTION json_object_field_text(json, text)
 RETURNS text
-AS 'MODULE_PATHNAME' , 'json_get_text'
+AS 'MODULE_PATHNAME' , 'json_object_field_text'
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_get_op(json, text)
+CREATE FUNCTION json_extract_path(the_json json, variadic path_elements text[])
 RETURNS json
-AS 'MODULE_PATHNAME' , 'json_get_op'
+AS 'MODULE_PATHNAME' , 'json_extract_path'
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_get_text_op(json, text)
+CREATE FUNCTION json_extract_path_text(the_json json, variadic path_elements text[])
 RETURNS text
-AS 'MODULE_PATHNAME' , 'json_get_text_op'
+AS 'MODULE_PATHNAME' , 'json_extract_path_text'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION json_extract_path_op(the_json json, path_elements text[])
+RETURNS json
+AS 'MODULE_PATHNAME' , 'json_extract_path'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION json_extract_path_text_op(the_json json, path_elements text[])
+RETURNS text
+AS 'MODULE_PATHNAME' , 'json_extract_path_text'
 LANGUAGE C STRICT IMMUTABLE;
 
 CREATE FUNCTION json_object_keys(the_json json)
 AS 'MODULE_PATHNAME' 
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_each_as_text(the_json json, key out text, value out text)
+CREATE FUNCTION json_each_text(the_json json, key out text, value out text)
 RETURNS SETOF record
 AS 'MODULE_PATHNAME' 
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_get_path(the_json json, path_element text[])
-RETURNS json
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION json_get_path_text(the_json json, path_element text[])
-RETURNS json
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION json_unnest(the_json json)
-RETURNS SETOF json
+CREATE FUNCTION json_array_elements(the_json json) 
+RETURNS TABLE (value json)
 AS 'MODULE_PATHNAME' 
 LANGUAGE C STRICT IMMUTABLE;
 
 LANGUAGE C IMMUTABLE;
 
 CREATE OPERATOR -> (
-       PROCEDURE = json_get_op,
+       PROCEDURE = json_object_field,
        LEFTARG = json, RIGHTARG = text
 );
 
 CREATE OPERATOR -> (
-       PROCEDURE = json_get,
+       PROCEDURE = json_array_element,
        LEFTARG = json, RIGHTARG = int
 );
 
 CREATE OPERATOR ->> (
-       PROCEDURE = json_get_text_op,
+       PROCEDURE = json_object_field_text,
        LEFTARG = json, RIGHTARG = text
 );
 
 CREATE OPERATOR ->> (
-       PROCEDURE = json_get_text,
+       PROCEDURE = json_array_element_text,
        LEFTARG = json, RIGHTARG = int
 );
 
 CREATE OPERATOR #> (
-       PROCEDURE = json_get_path,
+       PROCEDURE = json_extract_path_op,
        LEFTARG = json, RIGHTARG = text[]
 );
 
 CREATE OPERATOR #>> (
-       PROCEDURE = json_get_path_text,
+       PROCEDURE = json_extract_path_text_op,
        LEFTARG = json, RIGHTARG = text[]
 );
 
     STYPE = internal
 );
     
-
-
-

File sql/json_enhancements_no_hstore.sql

 -- complain if script is sourced in psql, rather than via CREATE EXTENSION
 \echo Use "CREATE EXTENSION json_enhancements" to load this file. \quit
 
-CREATE FUNCTION json_get(the_json json, element integer)
+CREATE FUNCTION json_array_element(the_json json, element integer)
 RETURNS json
-AS 'MODULE_PATHNAME' , 'json_get_int'
+AS 'MODULE_PATHNAME' , 'json_array_element'
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_get_text(the_json json, element integer)
+CREATE FUNCTION json_array_element_text(the_json json, element integer)
 RETURNS text
-AS 'MODULE_PATHNAME' , 'json_get_text_int'
+AS 'MODULE_PATHNAME' , 'json_array_element_text'
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_get(the_json json, variadic path_elements text[])
+CREATE FUNCTION json_object_field(json, text)
 RETURNS json
-AS 'MODULE_PATHNAME' , 'json_get'
+AS 'MODULE_PATHNAME' , 'json_object_field'
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_get_text(the_json json, variadic path_elements text[])
+CREATE FUNCTION json_object_field_text(json, text)
 RETURNS text
-AS 'MODULE_PATHNAME' , 'json_get_text'
+AS 'MODULE_PATHNAME' , 'json_object_field_text'
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_get_op(json, text)
+CREATE FUNCTION json_extract_path(the_json json, variadic path_elements text[])
 RETURNS json
-AS 'MODULE_PATHNAME' , 'json_get_op'
+AS 'MODULE_PATHNAME' , 'json_extract_path'
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_get_text_op(json, text)
+CREATE FUNCTION json_extract_path_text(the_json json, variadic path_elements text[])
 RETURNS text
-AS 'MODULE_PATHNAME' , 'json_get_text_op'
+AS 'MODULE_PATHNAME' , 'json_extract_path_text'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION json_extract_path_op(the_json json, path_elements text[])
+RETURNS json
+AS 'MODULE_PATHNAME' , 'json_extract_path'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION json_extract_path_text_op(the_json json, path_elements text[])
+RETURNS text
+AS 'MODULE_PATHNAME' , 'json_extract_path_text'
 LANGUAGE C STRICT IMMUTABLE;
 
 CREATE FUNCTION json_object_keys(the_json json)
 AS 'MODULE_PATHNAME' 
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_each_as_text(the_json json, key out text, value out text)
+CREATE FUNCTION json_each_text(the_json json, key out text, value out text)
 RETURNS SETOF record
 AS 'MODULE_PATHNAME' 
 LANGUAGE C STRICT IMMUTABLE;
 
-CREATE FUNCTION json_get_path(the_json json, path_element text[])
-RETURNS json
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION json_get_path_text(the_json json, path_element text[])
-RETURNS json
-AS 'MODULE_PATHNAME'
-LANGUAGE C STRICT IMMUTABLE;
-
-CREATE FUNCTION json_unnest(the_json json)
-RETURNS SETOF json
+CREATE FUNCTION json_array_elements(the_json json) 
+RETURNS TABLE (value json)
 AS 'MODULE_PATHNAME' 
 LANGUAGE C STRICT IMMUTABLE;
 
 LANGUAGE C IMMUTABLE;
 
 CREATE OPERATOR -> (
-       PROCEDURE = json_get_op,
+       PROCEDURE = json_object_field,
        LEFTARG = json, RIGHTARG = text
 );
 
 CREATE OPERATOR -> (
-       PROCEDURE = json_get,
+       PROCEDURE = json_array_element,
        LEFTARG = json, RIGHTARG = int
 );
 
 CREATE OPERATOR ->> (
-       PROCEDURE = json_get_text_op,
+       PROCEDURE = json_object_field_text,
        LEFTARG = json, RIGHTARG = text
 );
 
 CREATE OPERATOR ->> (
-       PROCEDURE = json_get_text,
+       PROCEDURE = json_array_element_text,
        LEFTARG = json, RIGHTARG = int
 );
 
 CREATE OPERATOR #> (
-       PROCEDURE = json_get_path,
+       PROCEDURE = json_extract_path_op,
        LEFTARG = json, RIGHTARG = text[]
 );
 
 CREATE OPERATOR #>> (
-       PROCEDURE = json_get_path_text,
+       PROCEDURE = json_extract_path_text_op,
        LEFTARG = json, RIGHTARG = text[]
 );
 
     STYPE = internal
 );
     
-
-
-

File src/json_extra.h

 extern Datum json_agg_finalfn(PG_FUNCTION_ARGS);
 
 /* functions in jsonfuncs.c */
-extern Datum json_get(PG_FUNCTION_ARGS);
-extern Datum json_get_text(PG_FUNCTION_ARGS);
-extern Datum json_get_int(PG_FUNCTION_ARGS);
-extern Datum json_get_text_int(PG_FUNCTION_ARGS);
-extern Datum json_get_op(PG_FUNCTION_ARGS);
-extern Datum json_get_text_op(PG_FUNCTION_ARGS);
-extern Datum json_get_path(PG_FUNCTION_ARGS);
-extern Datum json_get_path_text(PG_FUNCTION_ARGS);
+extern Datum json_object_field(PG_FUNCTION_ARGS);
+extern Datum json_object_field_text(PG_FUNCTION_ARGS);
+extern Datum json_array_element(PG_FUNCTION_ARGS);
+extern Datum json_array_element_text(PG_FUNCTION_ARGS);
+extern Datum json_extract_path(PG_FUNCTION_ARGS);
+extern Datum json_extract_path_text(PG_FUNCTION_ARGS);
 extern Datum json_object_keys(PG_FUNCTION_ARGS);
 extern Datum json_array_length(PG_FUNCTION_ARGS);
 extern Datum json_each(PG_FUNCTION_ARGS);
-extern Datum json_each_as_text(PG_FUNCTION_ARGS);
-extern Datum json_unnest(PG_FUNCTION_ARGS);
+extern Datum json_each_text(PG_FUNCTION_ARGS);
+extern Datum json_array_elements(PG_FUNCTION_ARGS);
 extern Datum json_populate_record(PG_FUNCTION_ARGS);
 extern Datum json_populate_recordset(PG_FUNCTION_ARGS);
 

File src/jsonfuncs.c

 static void get_array_element_end(void *state, bool isnull);
 static void get_scalar(void *state, char *token, JsonTokenType tokentype);
 
-/* common worker function for json_get* functions */
-static inline Datum get_all(PG_FUNCTION_ARGS, bool as_text);
+/* common worker function for json getter functions */
 static inline Datum get_path_all(PG_FUNCTION_ARGS, bool as_text);
-static inline text *get_worker(text *json, char *field, int elem_index, 
-							   char **tpath, int *ipath, int npath, 
-							   bool normalize_results);
+static inline text *get_worker(text *json, char *field, int elem_index,
+		   char **tpath, int *ipath, int npath,
+		   bool normalize_results);
 
 /* semantic action functions for json_array_length */
 static void alen_object_start(void *state);
 static void alen_scalar(void *state, char *token, JsonTokenType tokentype);
 static void alen_array_element_start(void *state, bool isnull);
 
+/* common worker for json_each* functions */
+static inline Datum each_worker(PG_FUNCTION_ARGS, bool as_text);
+
 /* semantic action functions for json_each */
 static void each_object_field_start(void *state, char *fname, bool isnull);
 static void each_object_field_end(void *state, char *fname, bool isnull);
 static void each_array_start(void *state);
 static void each_scalar(void *state, char *token, JsonTokenType tokentype);
 
-/* semantic action functions for json_unnest */
-static void unnest_object_start(void *state);
-static void unnest_array_element_start(void *state, bool isnull);
-static void unnest_array_element_end(void *state, bool isnull);
-static void unnest_scalar(void *state, char *token, JsonTokenType tokentype);
+/* semantic action functions for json_array_elements */
+static void elements_object_start(void *state);
+static void elements_array_element_start(void *state, bool isnull);
+static void elements_array_element_end(void *state, bool isnull);
+static void elements_scalar(void *state, char *token, JsonTokenType tokentype);
 
 /* turn a json object into a hash table */
 static HTAB *get_json_object_as_hash(text *json, char *funcname, bool use_json_as_text);
 	char	   *normalized_scalar;
 }	eachState, *EachState;
 
-/* state for json_unnest */
-typedef struct unnestState
+/* state for json_array_elements */
+typedef struct elementsState
 {
 	JsonLexContext *lex;
 	Tuplestorestate *tuple_store;
 	TupleDesc	ret_tdesc;
 	MemoryContext tmp_cxt;
 	char	   *result_start;
-}	unnestState, *UnnestState;
+}	elementsState, *ElementsState;
 
 /* state for get_json_object_as_hash */
 typedef struct jhashState
 
 PG_FUNCTION_INFO_V1(json_object_keys);
 
+
 Datum
 json_object_keys(PG_FUNCTION_ARGS)
 {
 }
 
 /*
- * json_get* functions
- * json_get and json_get_text are variadic forms
- * json_get_path and json_get_path_text take an array of text for the path
- * Note: we have separate _int and _op versions of these function to keep the
- * opr_sanity checks happy.
+ * json getter functions
+ * these implement the -> ->> #> and #>> operators
+ * and the json_extract_path*(json, text, ...) functions
  */
 
-
-PG_FUNCTION_INFO_V1(json_get);
+PG_FUNCTION_INFO_V1(json_object_field);
 
 Datum
-json_get(PG_FUNCTION_ARGS)
+json_object_field(PG_FUNCTION_ARGS)
 {
-	/* not the text variant, so set as_text to false. */
-	return get_all(fcinfo, false);
-}
-
-PG_FUNCTION_INFO_V1(json_get_text);
-
-Datum
-json_get_text(PG_FUNCTION_ARGS)
-{
-	/* the text variant, so set as_text to true. */
-	return get_all(fcinfo, true);
-}
+	text	   *json = PG_GETARG_TEXT_P(0);
+	text	   *result;
+	text	   *fname = PG_GETARG_TEXT_P(1);
+	char	   *fnamestr = text_to_cstring(fname);
 
-PG_FUNCTION_INFO_V1(json_get_int);
+	result = get_worker(json, fnamestr, -1, NULL, NULL, -1, false);
 
-Datum
-json_get_int(PG_FUNCTION_ARGS)
-{
-	/* not the text variant, so set as_text to false. */
-	return get_all(fcinfo, false);
+	if (result != NULL)
+		PG_RETURN_TEXT_P(result);
+	else
+		PG_RETURN_NULL();
 }
 
-PG_FUNCTION_INFO_V1(json_get_text_int);
+PG_FUNCTION_INFO_V1(json_object_field_text);
 
 Datum
-json_get_text_int(PG_FUNCTION_ARGS)
+json_object_field_text(PG_FUNCTION_ARGS)
 {
-	/* the text variant, so set as_text to true. */
-	return get_all(fcinfo, true);
-}
+	text	   *json = PG_GETARG_TEXT_P(0);
+	text	   *result;
+	text	   *fname = PG_GETARG_TEXT_P(1);
+	char	   *fnamestr = text_to_cstring(fname);
 
-PG_FUNCTION_INFO_V1(json_get_op);
+	result = get_worker(json, fnamestr, -1, NULL, NULL, -1, true);
 
-Datum
-json_get_op(PG_FUNCTION_ARGS)
-{
-	/* not the text variant, so set as_text to false. */
-	return get_all(fcinfo, false);
+	if (result != NULL)
+		PG_RETURN_TEXT_P(result);
+	else
+		PG_RETURN_NULL();
 }
 
-PG_FUNCTION_INFO_V1(json_get_text_op);
+PG_FUNCTION_INFO_V1(json_array_element);
 
 Datum
-json_get_text_op(PG_FUNCTION_ARGS)
+json_array_element(PG_FUNCTION_ARGS)
 {
-	/* the text variant, so set as_text to true. */
-	return get_all(fcinfo, true);
-}
-
-static inline Datum
-get_all(PG_FUNCTION_ARGS, bool as_text)
-{
-	text *json = PG_GETARG_TEXT_P(0);
-	text *result = NULL;
+	text	   *json = PG_GETARG_TEXT_P(0);
+	text	   *result;
+	int			element = PG_GETARG_INT32(1);
 
-	Oid         element_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
+	result = get_worker(json, NULL, element, NULL, NULL, -1, false);
 
-	if (element_type == INT4OID)
-	{
-		int element =  PG_GETARG_INT32(1);
-		
-		result = get_worker(json, NULL, element, NULL, NULL, -1, as_text);
-	}
-	else if (element_type == TEXTOID)
-	{
-		text	   *fname = PG_GETARG_TEXT_P(1);
-		char	   *fnamestr = text_to_cstring(fname);
-
-		result = get_worker(json, fnamestr, -1, NULL, NULL, -1, as_text);
-	}
+	if (result != NULL)
+		PG_RETURN_TEXT_P(result);
 	else
-	{
-		/* must be a text array */
-		
-		ArrayType  *path = PG_GETARG_ARRAYTYPE_P(1);
-		Datum	   *pathtext;
-		bool	   *pathnulls;
-		int			npath;
-		char	  **tpath;
-		int        *ipath;
-		int			i;
-		long        ind;
-		char       *endptr;
-
-		if (array_contains_nulls(path))
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("cannot call function with null path elements")));
-
+		PG_RETURN_NULL();
+}
 
-		deconstruct_array(path, TEXTOID, -1, false, 'i',
-						  &pathtext, &pathnulls, &npath);
+PG_FUNCTION_INFO_V1(json_array_element_text);
 
-		/* 
-		 * the search is a bit optimized for a single element path.
-		 */
-		if (npath == 1)
-		{
-			char	   *fname = TextDatumGetCString(pathtext[0]);
-			
-			/* 
-			 * XXX is it worth checking for an int string here?
-			 * For the moment probably not. We'd have top fall back on the
-			 * multi-element path call if we found one, and it would be messy.
-			 * The alternative would be to abandon this use of the optimized
-			 * single element call.
-			 */
-			result = get_worker(json, fname, -1, NULL, NULL, -1, as_text);
-		}
-		else
-		{
+Datum
+json_array_element_text(PG_FUNCTION_ARGS)
+{
+	text	   *json = PG_GETARG_TEXT_P(0);
+	text	   *result;
+	int			element = PG_GETARG_INT32(1);
 
-			tpath = palloc(npath * sizeof(char *));
-			ipath = palloc(npath * sizeof(int));
-		
-			for (i = 0; i < npath; i++)
-			{
-				tpath[i] = TextDatumGetCString(pathtext[i]);
-				if (*tpath[i] == '\0')
-					ereport(
-						ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("cannot call function with empty path elements")));
-				ind = strtol(tpath[i], &endptr, 10);
-				if (*endptr == '\0' && ind <= INT_MAX && ind >= 0)
-					ipath[i] = (int) ind;
-				else
-					ipath[i] = -1;
-			}
-			
-			result = get_worker(json, NULL, -1, tpath, ipath, npath, as_text);
-		}
-		
-	}
+	result = get_worker(json, NULL, element, NULL, NULL, -1, true);
 
 	if (result != NULL)
 		PG_RETURN_TEXT_P(result);
 		PG_RETURN_NULL();
 }
 
-PG_FUNCTION_INFO_V1(json_get_path);
+PG_FUNCTION_INFO_V1(json_extract_path);
 
 Datum
-json_get_path(PG_FUNCTION_ARGS)
+json_extract_path(PG_FUNCTION_ARGS)
 {
-	/* not the text variant, so set as_text to false. */
 	return get_path_all(fcinfo, false);
 }
 
-PG_FUNCTION_INFO_V1(json_get_path_text);
+PG_FUNCTION_INFO_V1(json_extract_path_text);
 
 Datum
-json_get_path_text(PG_FUNCTION_ARGS)
+json_extract_path_text(PG_FUNCTION_ARGS)
 {
-	/* the text variant, so set as_text to true. */
 	return get_path_all(fcinfo, true);
 }
 
-
 static inline Datum
 get_path_all(PG_FUNCTION_ARGS, bool as_text)
 {
 
 	tpath = palloc(npath * sizeof(char *));
 	ipath = palloc(npath * sizeof(int));
-	
+
 
 	for (i = 0; i < npath; i++)
 	{
 			ereport(
 					ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("cannot call function with empty path elements")));
+				   errmsg("cannot call function with empty path elements")));
+
 		/*
 		 * we have no idea at this stage what structure the document is so
 		 * just convert anything in the path that we can to an integer and set
 	if (_state->lex->lex_level == 0 && _state->search_type == JSON_SEARCH_ARRAY)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot call json_get(int) on a non-array")));
+				 errmsg("cannot extract array element from a non-array")));
 }
 
 static void
 	if (lex_level == 1 && _state->search_type == JSON_SEARCH_OBJECT &&
 		strcmp(fname, _state->search_term) == 0)
 	{
-		
+
 		_state->tresult = NULL;
 		_state->result_start = NULL;
 		get_next = true;
 		 */
 		int			len = _state->lex->prev_token_terminator - _state->result_start;
 
-		if (isnull  && _state->normalize_results)
+		if (isnull && _state->normalize_results)
 			_state->tresult = (text *) NULL;
 		else
 			_state->tresult = cstring_to_text_with_len(_state->result_start, len);
 	if (lex_level == 0 && _state->search_type == JSON_SEARCH_OBJECT)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot call json_get(fieldname) on a non-object")));
+				 errmsg("cannot extract field from a non-object")));
 	/* initialize array count for this nesting level */
 	if (_state->search_type == JSON_SEARCH_PATH &&
 		lex_level <= _state->npath)
 	}
 	if (get_last && _state->result_start != NULL)
 	{
-		int	 len = _state->lex->prev_token_terminator - _state->result_start;
+		int			len = _state->lex->prev_token_terminator - _state->result_start;
 
-		if (isnull  && _state->normalize_results)
+		if (isnull && _state->normalize_results)
 			_state->tresult = (text *) NULL;
 		else
 			_state->tresult = cstring_to_text_with_len(_state->result_start, len);
 	if (_state->lex->lex_level == 0 && _state->search_type != JSON_SEARCH_PATH)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot call json_get on a scalar")));
+				 errmsg("cannot extract element from a scalar")));
 	if (_state->next_scalar)
 	{
 		/* a de-escaped text value is wanted, so supply it */
 
 /*
  * These next two check ensure that the json is an array (since it can't be
- * a scala or an object).
+ * a scalar or an object).
  */
 
 static void
 	if (_state->lex->lex_level == 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot call json_array_length on an object")));
+				 errmsg("cannot get array length of a non-array")));
 }
 
 static void
 	if (_state->lex->lex_level == 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot call json_array_length on a scalar")));
+				 errmsg("cannot get array length of a scalar")));
 }
 
 static void
 }
 
 /*
- * SQL function json_each
+ * SQL function json_each and json_each_text
  *
  * decompose a json object into key value pairs.
  *
- * Unlike json_object_keys() this SRF operates in materialize mode,
- * stashing its results into a Tuplestore object as it goes.
- * The constriction of tuples is done using a temporary memory context
+ * Unlike json_object_keys() these SRFs operate in materialize mode,
+ * stashing results into a Tuplestore object as they go.
+ * The construction of tuples is done using a temporary memory context
  * that is cleared out after each tuple is built.
  */
 
 Datum
 json_each(PG_FUNCTION_ARGS)
 {
-	text	   *json = PG_GETARG_TEXT_P(0);
-	JsonLexContext *lex = makeJsonLexContext(json, true);
-	JsonSemAction sem;
-	ReturnSetInfo *rsi;
-	MemoryContext old_cxt;
-	TupleDesc	tupdesc;
-	EachState	state;
-
-	state = palloc0(sizeof(eachState));
-	sem = palloc0(sizeof(jsonSemAction));
-
-	rsi = (ReturnSetInfo *) fcinfo->resultinfo;
-
-	if (!rsi || !IsA(rsi, ReturnSetInfo) ||
-		(rsi->allowedModes & SFRM_Materialize) == 0 ||
-		rsi->expectedDesc == NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("set-valued function called in context that "
-						"cannot accept a set")));
-
-
-	rsi->returnMode = SFRM_Materialize;
-
-	(void) get_call_result_type(fcinfo, NULL, &tupdesc);
-
-	/* make these in a sufficiently long-lived memory context */
-	old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
-
-	state->ret_tdesc = CreateTupleDescCopy(tupdesc);
-	BlessTupleDesc(state->ret_tdesc);
-	state->tuple_store =
-		tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
-							  false, work_mem);
-
-	MemoryContextSwitchTo(old_cxt);
-
-	sem->semstate = (void *) state;
-	sem->array_start = each_array_start;
-	sem->scalar = each_scalar;
-	sem->object_field_start = each_object_field_start;
-	sem->object_field_end = each_object_field_end;
-
-	state->normalize_results = false;
-	state->next_scalar = false;
-
-	state->lex = lex;
-	state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
-										   "json_each temporary cxt",
-										   ALLOCSET_DEFAULT_MINSIZE,
-										   ALLOCSET_DEFAULT_INITSIZE,
-										   ALLOCSET_DEFAULT_MAXSIZE);
-
-	pg_parse_json(lex, sem);
-
-	rsi->setResult = state->tuple_store;
-	rsi->setDesc = state->ret_tdesc;
-
-	PG_RETURN_NULL();
+	return each_worker(fcinfo, false);
 }
 
-/*
- * SQL function json_each_as_text
- *
- * decompose a json object into key value pairs with
- * de-escaped scalar string values.
- *
- * See also comments for json_each
- */
-
-PG_FUNCTION_INFO_V1(json_each_as_text);
+PG_FUNCTION_INFO_V1(json_each_text);
 
 Datum
-json_each_as_text(PG_FUNCTION_ARGS)
+json_each_text(PG_FUNCTION_ARGS)
+{
+	return each_worker(fcinfo, true);
+}
+
+static inline Datum
+each_worker(PG_FUNCTION_ARGS, bool as_text)
 {
 	text	   *json = PG_GETARG_TEXT_P(0);
 	JsonLexContext *lex = makeJsonLexContext(json, true);
 	sem->object_field_start = each_object_field_start;
 	sem->object_field_end = each_object_field_end;
 
-	/* next line is what's different from json_each */
-	state->normalize_results = true;
+	state->normalize_results = as_text;
 	state->next_scalar = false;
 
 	state->lex = lex;
 	text	   *val;
 	HeapTuple	tuple;
 	Datum		values[2];
-	bool        nulls[2] = {false, false};
+	bool		nulls[2] = {false, false};
 
 	/* skip over nested objects */
 	if (_state->lex->lex_level != 1)
 	if (_state->lex->lex_level == 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot call json_each on an array")));
+				 errmsg("cannot deconstruct an array as an object")));
 }
 
 static void
 	if (_state->lex->lex_level == 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot call json_each on a scalar")));
+				 errmsg("cannot deconstruct a scalar")));
 
 	/* supply de-escaped value if required */
 	if (_state->next_scalar)
 }
 
 /*
- * SQL function json_unnest
+ * SQL function json_array_elements
  *
  * get the elements from a json array
  *
  * a lot of this processing is similar to the json_each* functions
  */
 
-PG_FUNCTION_INFO_V1(json_unnest);
+PG_FUNCTION_INFO_V1(json_array_elements);
 
 Datum
-json_unnest(PG_FUNCTION_ARGS)
+json_array_elements(PG_FUNCTION_ARGS)
 {
 	text	   *json = PG_GETARG_TEXT_P(0);
 
-	/* unnest doesn't need any escaped strings, so use false here */
+	/* array_elements doesn't need any escaped strings, so use false here */
 	JsonLexContext *lex = makeJsonLexContext(json, false);
 	JsonSemAction sem;
 	ReturnSetInfo *rsi;
 	MemoryContext old_cxt;
 	TupleDesc	tupdesc;
-	UnnestState state;
+	ElementsState state;
 
-	state = palloc0(sizeof(unnestState));
+	state = palloc0(sizeof(elementsState));
 	sem = palloc0(sizeof(jsonSemAction));
 
 	rsi = (ReturnSetInfo *) fcinfo->resultinfo;
 	MemoryContextSwitchTo(old_cxt);
 
 	sem->semstate = (void *) state;
-	sem->object_start = unnest_object_start;
-	sem->scalar = unnest_scalar;
-	sem->array_element_start = unnest_array_element_start;
-	sem->array_element_end = unnest_array_element_end;
+	sem->object_start = elements_object_start;
+	sem->scalar = elements_scalar;
+	sem->array_element_start = elements_array_element_start;
+	sem->array_element_end = elements_array_element_end;
 
 	state->lex = lex;
 	state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
-										   "json_unnest temporary cxt",
+										 "json_array_elements temporary cxt",
 										   ALLOCSET_DEFAULT_MINSIZE,
 										   ALLOCSET_DEFAULT_INITSIZE,
 										   ALLOCSET_DEFAULT_MAXSIZE);
 }
 
 static void
-unnest_array_element_start(void *state, bool isnull)
+elements_array_element_start(void *state, bool isnull)
 {
-	UnnestState _state = (UnnestState) state;
+	ElementsState _state = (ElementsState) state;
 
 	/* save a pointer to where the value starts */
 	if (_state->lex->lex_level == 1)
 }
 
 static void
-unnest_array_element_end(void *state, bool isnull)
+elements_array_element_end(void *state, bool isnull)
 {
-	UnnestState _state = (UnnestState) state;
+	ElementsState _state = (ElementsState) state;
 	MemoryContext old_cxt;
 	int			len;
 	text	   *val;
 }
 
 static void
-unnest_object_start(void *state)
+elements_object_start(void *state)
 {
-	UnnestState _state = (UnnestState) state;
+	ElementsState _state = (ElementsState) state;
 
 	/* json structure check */
 	if (_state->lex->lex_level == 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot call json_unnest on an object")));
+				 errmsg("cannot call json_array_elements on a non-array")));
 }
 
 static void
-unnest_scalar(void *state, char *token, JsonTokenType tokentype)
+elements_scalar(void *state, char *token, JsonTokenType tokentype)
 {
-	UnnestState _state = (UnnestState) state;
+	ElementsState _state = (ElementsState) state;
 
 	/* json structure check */
 	if (_state->lex->lex_level == 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot call json_unnest on a scalar")));
+				 errmsg("cannot call json_array_elements on a scalar")));
 
 	/*
-	 * json_unnest always returns json, so there's no need to think about
-	 * de-escaped values here.
+	 * json_array_elements always returns json, so there's no need to think
+	 * about de-escaped values here.
 	 */
 }
 
 
 	hashentry = hash_search(_state->hash, name, HASH_ENTER, &found);
 
-	/* 
-	 * found being true indicates a duplicate. We don't do anything about that,
-	 * a later field with the same name overrides the earlier field.
+	/*
+	 * found being true indicates a duplicate. We don't do anything about
+	 * that, a later field with the same name overrides the earlier field.
 	 */
 
 	hashentry->isnull = isnull;
 	if (lex_level == 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot call populate_recordset on an object")));
+				 errmsg("cannot call json_populate_recordset on an object")));
 	else if (lex_level > 1 && !_state->use_json_as_text)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-			  errmsg("cannot call populate_recordset with nested objects")));
+		 errmsg("cannot call json_populate_recordset with nested objects")));
 
 	/* set up a new hash for this entry */
 	memset(&ctl, 0, sizeof(ctl));
 	if (_state->lex->lex_level != 0 && !_state->use_json_as_text)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-			   errmsg("cannot call populate_recordset with nested arrays")));
+		  errmsg("cannot call json_populate_recordset with nested arrays")));
 }
 
 static void
 	if (_state->lex->lex_level == 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("cannot call populate_recordset on a scalar")));
+				 errmsg("cannot call json_populate_recordset on a scalar")));
 
 	if (_state->lex->lex_level == 2)
 		_state->saved_scalar = token;
 		if (!_state->use_json_as_text)
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-			   errmsg("cannot call populate_recordset on a nested object")));
+					 errmsg("cannot call json_populate_recordset on a nested object")));
 		_state->save_json_start = _state->lex->token_start;
 	}
 	else
 
 	hashentry = hash_search(_state->json_hash, name, HASH_ENTER, &found);
 
-	/* 
-	 * found being true indicates a duplicate. We don't do anything about that,
-	 * a later field with the same name overrides the earlier field.
+	/*
+	 * found being true indicates a duplicate. We don't do anything about
+	 * that, a later field with the same name overrides the earlier field.
 	 */
 
 	hashentry->isnull = isnull;

File test/expected/json.out

  {"f1":[5,6,7,8,9,10]}
 (1 row)
 
+--json_agg
+SELECT json_agg(q)
+  FROM ( SELECT $$a$$ || x AS b, y AS c,
+               ARRAY[ROW(x.*,ARRAY[1,2,3]),
+               ROW(y.*,ARRAY[4,5,6])] AS z
+         FROM generate_series(1,2) x,
+              generate_series(4,5) y) q;
+                               json_agg                                
+-----------------------------------------------------------------------
+ [{"b":"a1","c":4,"z":[{"f1":1,"f2":[1,2,3]},{"f1":4,"f2":[4,5,6]}]}, +
+  {"b":"a1","c":5,"z":[{"f1":1,"f2":[1,2,3]},{"f1":5,"f2":[4,5,6]}]}, +
+  {"b":"a2","c":4,"z":[{"f1":2,"f2":[1,2,3]},{"f1":4,"f2":[4,5,6]}]}, +
+  {"b":"a2","c":5,"z":[{"f1":2,"f2":[1,2,3]},{"f1":5,"f2":[4,5,6]}]}]
+(1 row)
+
+SELECT json_agg(q)
+  FROM rows q;
+       json_agg        
+-----------------------
+ [{"x":1,"y":"txt1"}, +
+  {"x":2,"y":"txt2"}, +
+  {"x":3,"y":"txt3"}]
+(1 row)
+
 -- non-numeric output
 SELECT row_to_json(q)
 FROM (SELECT 'NaN'::float8 AS "float8field") q;
  {"jsonfield":{"a":1,"b": [2,3,4,"d","e","f"],"c":{"p":1,"q":2}}}
 (1 row)
 
---json_agg
-SELECT json_agg(q)
-  FROM ( SELECT $$a$$ || x AS b, y AS c,
-               ARRAY[ROW(x.*,ARRAY[1,2,3]),
-               ROW(y.*,ARRAY[4,5,6])] AS z
-         FROM generate_series(1,2) x,
-              generate_series(4,5) y) q;
-                               json_agg                                
------------------------------------------------------------------------
- [{"b":"a1","c":4,"z":[{"f1":1,"f2":[1,2,3]},{"f1":4,"f2":[4,5,6]}]}, +
-  {"b":"a1","c":5,"z":[{"f1":1,"f2":[1,2,3]},{"f1":5,"f2":[4,5,6]}]}, +
-  {"b":"a2","c":4,"z":[{"f1":2,"f2":[1,2,3]},{"f1":4,"f2":[4,5,6]}]}, +
-  {"b":"a2","c":5,"z":[{"f1":2,"f2":[1,2,3]},{"f1":5,"f2":[4,5,6]}]}]
-(1 row)
-
-SELECT json_agg(q)
-  FROM rows q;
-       json_agg        
------------------------
- [{"x":1,"y":"txt1"}, +
-  {"x":2,"y":"txt2"}, +
-  {"x":3,"y":"txt3"}]
-(1 row)
-
- 
 -- json extraction functions
 CREATE TEMP TABLE test_json (
        json_type text,
 ('scalar','"a scalar"'),
 ('array','["zero", "one","two",null,"four","five"]'),
 ('object','{"field1":"val1","field2":"val2","field3":null}');
-SELECT json_get(test_json,'x') 
+SELECT test_json -> 'x' 
 FROM test_json
 WHERE json_type = 'scalar';
-ERROR:  cannot call json_get on a scalar
-SELECT json_get(test_json,'x') 
+ERROR:  cannot extract element from a scalar
+SELECT test_json -> 'x' 
 FROM test_json
 WHERE json_type = 'array';
-ERROR:  cannot call json_get(fieldname) on a non-object
-SELECT json_get(test_json,'x') 
+ERROR:  cannot extract field from a non-object
+SELECT test_json -> 'x' 
 FROM test_json
 WHERE json_type = 'object';
- json_get 
+ ?column? 
 ----------
  
 (1 row)
 
-SELECT json_get(test_json,'field2') 
-FROM test_json
-WHERE json_type = 'object';
- json_get 
-----------
- "val2"
-(1 row)
-
 SELECT test_json->'field2'
 FROM test_json
 WHERE json_type = 'object';
  val2
 (1 row)
 
-SELECT json_get(test_json,2) 
+SELECT test_json -> 2 
 FROM test_json
 WHERE json_type = 'scalar';
-ERROR:  cannot call json_get on a scalar
-SELECT json_get(test_json,2) 
+ERROR:  cannot extract element from a scalar
+SELECT test_json -> 2 
 FROM test_json
 WHERE json_type = 'array';
- json_get 
+ ?column? 
 ----------
  "two"
 (1 row)
 
-SELECT json_get(test_json,2)
+SELECT test_json -> 2
 FROM test_json
 WHERE json_type = 'object';
-ERROR:  cannot call json_get(int) on a non-array
-SELECT json_get(test_json,2) 
-FROM test_json
-WHERE json_type = 'array';
- json_get 
-----------
- "two"
-(1 row)
-
-SELECT test_json->2 
-FROM test_json
-WHERE json_type = 'array';
- ?column? 
-----------
- "two"
-(1 row)
-
+ERROR:  cannot extract array element from a non-array
 SELECT test_json->>2
 FROM test_json
 WHERE json_type = 'array';
 (1 row)
 
 SELECT json_array_length('{"f1":1,"f2":[5,6]}');
-ERROR:  cannot call json_array_length on an object
+ERROR:  cannot get array length of a non-array
 SELECT json_array_length('4');
-ERROR:  cannot call json_array_length on a scalar
+ERROR:  cannot get array length of a scalar
 -- each
 select json_each('{"f1":[1,2,3],"f2":{"f3":1},"f4":null}');
      json_each     
  f6  | "stringy"
 (5 rows)
 
-select json_each_as_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":"null"}');
- json_each_as_text 
+select json_each_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":"null"}');
+  json_each_text   
 -------------------
  (f1,"[1,2,3]")
  (f2,"{""f3"":1}")
  (f5,null)
 (4 rows)
 
-select * from json_each_as_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":99,"f6":"stringy"}') q;
+select * from json_each_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":99,"f6":"stringy"}') q;
  key |  value   
 -----+----------
  f1  | [1,2,3]
  f6  | stringy
 (5 rows)
 
--- variadic get, get_text
-select json_get('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
- json_get  
------------
+-- extract_path, extract_path_as_text
+select json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
+ json_extract_path 
+-------------------
  "stringy"
 (1 row)
 
-select json_get('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
- json_get 
-----------
+select json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
+ json_extract_path 
+-------------------
  {"f3":1}
 (1 row)
 
-select json_get('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
- json_get 
-----------
+select json_extract_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
+ json_extract_path 
+-------------------
  "f3"
 (1 row)
 
-select json_get('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
- json_get 
-----------
+select json_extract_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
+ json_extract_path 
+-------------------
  1
 (1 row)
 
-select json_get_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
- json_get_text 
----------------
+select json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
+ json_extract_path_text 
+------------------------
  stringy
 (1 row)
 
-select json_get_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
- json_get_text 
----------------
+select json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
+ json_extract_path_text 
+------------------------
  {"f3":1}
 (1 row)
 
-select json_get_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
- json_get_text 
----------------
+select json_extract_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
+ json_extract_path_text 
+------------------------
  f3
 (1 row)
 
-select json_get_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
- json_get_text 
----------------
+select json_extract_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
+ json_extract_path_text 
+------------------------
  1
 (1 row)
 
--- get nulls
-select json_get('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') is null as expect_false;
+-- extract_path nulls
+select json_extract_path('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') is null as expect_false;
  expect_false 
 --------------
  f
 (1 row)
 
-select json_get_text('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') is null as expect_true;
+select json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') is null as expect_true;
  expect_true 
 -------------
  t
 (1 row)
 
-select json_get('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') is null as expect_false;
+select json_extract_path('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') is null as expect_false;
  expect_false 
 --------------
  f
 (1 row)
 
-select json_get_text('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') is null as expect_true;
+select json_extract_path_text('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') is null as expect_true;
  expect_true 
 -------------
  t
 (1 row)
 
--- get_path
-select json_get_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}', array['f4','f6']);
- json_get_path 
----------------
- "stringy"
-(1 row)
-
-select json_get_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}', array['f2']);
- json_get_path 
----------------
- {"f3":1}
-(1 row)
-
-select json_get_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}', array['f2','0']);
- json_get_path 
----------------
- "f3"
-(1 row)
-
-select json_get_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}', array['f2','1']);
- json_get_path 
----------------
- 1
-(1 row)
-
-select json_get_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}', array['f4','f6']);
- json_get_path_text 
---------------------
- stringy
-(1 row)
-
-select json_get_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}', array['f2']);
- json_get_path_text 
---------------------
- {"f3":1}
-(1 row)
-
-select json_get_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}', array['f2','0']);
- json_get_path_text 
---------------------
- f3
-(1 row)
-
-select json_get_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}', array['f2','1']);
- json_get_path_text 
---------------------
- 1
-(1 row)
-
--- get_path operators
+-- extract_path operators
 select '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::json#>array['f4','f6'];
  ?column?  
 -----------
  1
 (1 row)
 
---unnest
-select json_unnest('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]');
-      json_unnest      
+-- array_elements
+select json_array_elements('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]');
+  json_array_elements  
 -----------------------
  1
  true
  false
 (6 rows)
 
-select * from json_unnest('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]') q;
-           q           
+select * from json_array_elements('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]') q;
+         value         
 -----------------------
  1
  true
 (2 rows)
 
 select * from json_populate_recordset(row('def',99,null)::jpop,'[{"a":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]') q;
-ERROR:  cannot call populate_recordset on a nested object
+ERROR:  cannot call json_populate_recordset on a nested object
 select * from json_populate_recordset(row('def',99,null)::jpop,'[{"c":[100,200,300],"x":43.2},{"a":{"z":true},"b":3,"c":"2012-01-20 10:42:53"}]') q;
-ERROR:  cannot call populate_recordset on a nested object
+ERROR:  cannot call json_populate_recordset on a nested object

File test/sql/json.sql

 
 SELECT row_to_json(row((select array_agg(x) as d from generate_series(5,10) x)),false);
 
+--json_agg
+
+SELECT json_agg(q)
+  FROM ( SELECT $$a$$ || x AS b, y AS c,
+               ARRAY[ROW(x.*,ARRAY[1,2,3]),
+               ROW(y.*,ARRAY[4,5,6])] AS z
+         FROM generate_series(1,2) x,
+              generate_series(4,5) y) q;
+
+SELECT json_agg(q)
+  FROM rows q;
+
 -- non-numeric output
 SELECT row_to_json(q)
 FROM (SELECT 'NaN'::float8 AS "float8field") q;
 SELECT row_to_json(q)
 FROM (SELECT '{"a":1,"b": [2,3,4,"d","e","f"],"c":{"p":1,"q":2}}'::json AS "jsonfield") q;
 
---json_agg
-
-SELECT json_agg(q)
-  FROM ( SELECT $$a$$ || x AS b, y AS c,
-               ARRAY[ROW(x.*,ARRAY[1,2,3]),
-               ROW(y.*,ARRAY[4,5,6])] AS z
-         FROM generate_series(1,2) x,
-              generate_series(4,5) y) q;
-SELECT json_agg(q)
-  FROM rows q;
- 
 
 -- json extraction functions
 
 ('array','["zero", "one","two",null,"four","five"]'),
 ('object','{"field1":"val1","field2":"val2","field3":null}');
 
-SELECT json_get(test_json,'x') 
+SELECT test_json -> 'x' 
 FROM test_json
 WHERE json_type = 'scalar';
 
-SELECT json_get(test_json,'x') 
+SELECT test_json -> 'x' 
 FROM test_json
 WHERE json_type = 'array';
 
-SELECT json_get(test_json,'x') 
-FROM test_json
-WHERE json_type = 'object';
-
-SELECT json_get(test_json,'field2') 
+SELECT test_json -> 'x' 
 FROM test_json
 WHERE json_type = 'object';
 
 FROM test_json
 WHERE json_type = 'object';
 
-SELECT json_get(test_json,2) 
+SELECT test_json -> 2 
 FROM test_json
 WHERE json_type = 'scalar';
 
-SELECT json_get(test_json,2) 
+SELECT test_json -> 2 
 FROM test_json
 WHERE json_type = 'array';
 
-SELECT json_get(test_json,2)
+SELECT test_json -> 2
 FROM test_json
 WHERE json_type = 'object';
 
-SELECT json_get(test_json,2) 
-FROM test_json
-WHERE json_type = 'array';
-
-SELECT test_json->2 
-FROM test_json
-WHERE json_type = 'array';
-
 SELECT test_json->>2
 FROM test_json
 WHERE json_type = 'array';
 select json_each('{"f1":[1,2,3],"f2":{"f3":1},"f4":null}');
 select * from json_each('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":99,"f6":"stringy"}') q;
 
-select json_each_as_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":"null"}');
-select * from json_each_as_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":99,"f6":"stringy"}') q;
-
--- variadic get, get_text
-
-select json_get('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
-select json_get('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
-select json_get('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
-select json_get('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
-select json_get_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
-select json_get_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
-select json_get_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
-select json_get_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
+select json_each_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":"null"}');
+select * from json_each_text('{"f1":[1,2,3],"f2":{"f3":1},"f4":null,"f5":99,"f6":"stringy"}') q;
 
--- get nulls
+-- extract_path, extract_path_as_text
 
-select json_get('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') is null as expect_false;
-select json_get_text('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') is null as expect_true;
-select json_get('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') is null as expect_false;
-select json_get_text('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') is null as expect_true;
+select json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
+select json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
+select json_extract_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
+select json_extract_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
+select json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f4','f6');
+select json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}','f2');
+select json_extract_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',0::text);
+select json_extract_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}','f2',1::text);
 
--- get_path
+-- extract_path nulls
 
-select json_get_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}', array['f4','f6']);
-select json_get_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}', array['f2']);
-select json_get_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}', array['f2','0']);
-select json_get_path('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}', array['f2','1']);
-select json_get_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}', array['f4','f6']);
-select json_get_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}', array['f2']);
-select json_get_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}', array['f2','0']);
-select json_get_path_text('{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}', array['f2','1']);
+select json_extract_path('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') is null as expect_false;
+select json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":null,"f6":"stringy"}}','f4','f5') is null as expect_true;
+select json_extract_path('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') is null as expect_false;
+select json_extract_path_text('{"f2":{"f3":1},"f4":[0,1,2,null]}','f4','3') is null as expect_true;
 
--- get_path operators
+-- extract_path operators
 
 select '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::json#>array['f4','f6'];
 select '{"f2":{"f3":1},"f4":{"f5":99,"f6":"stringy"}}'::json#>array['f2'];
 select '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::json#>>'{f2,0}';
 select '{"f2":["f3",1],"f4":{"f5":99,"f6":"stringy"}}'::json#>>'{f2,1}';
 
---unnest
+-- array_elements
 
-select json_unnest('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]');
-select * from json_unnest('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]') q;
+select json_array_elements('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]');
+select * from json_array_elements('[1,true,[1,[2,3]],null,{"f1":1,"f2":[7,8,9]},false]') q;
 
 -- populate_record
 create type jpop as (a text, b int, c timestamp);