Re: [HACKERS] [PATCH] Implement json_array_elements_text

2014-01-28 Thread Andrew Dunstan


On 01/20/2014 10:34 PM, Andrew Dunstan wrote:


On 01/20/2014 09:58 PM, Laurence Rowe wrote:

Following the discussion on pgsql-general, I thought I'd have a go
implementing json_array_elements_text following the same pattern as
json_each_text. The function makes it possible to join elements of a
json array onto a table,


Can we sneak this very small feature into 9.4? I'm happy to take on 
the review etc.






I'm going to take silence as consent and try to get the updated version 
of this committed today.


cheers

andrew



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH] Implement json_array_elements_text

2014-01-20 Thread Laurence Rowe
On 20 January 2014 18:58, Laurence Rowe  wrote:

> Following the discussion on pgsql-general, I thought I'd have a go
> implementing json_array_elements_text following the same pattern as
> json_each_text.
>

This updated patch makes the return type of ``json_array_elements_text``
text rather than json, I'd not set it correctly in pg_proc.h.

Laurence


0001-Implement-json_array_elements_text.patch
Description: Binary data

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] [PATCH] Implement json_array_elements_text

2014-01-20 Thread Andrew Dunstan


On 01/20/2014 09:58 PM, Laurence Rowe wrote:

Following the discussion on pgsql-general, I thought I'd have a go
implementing json_array_elements_text following the same pattern as
json_each_text. The function makes it possible to join elements of a
json array onto a table,


Can we sneak this very small feature into 9.4? I'm happy to take on the 
review etc.


cheers

andrew


--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


[HACKERS] [PATCH] Implement json_array_elements_text

2014-01-20 Thread Laurence Rowe
Following the discussion on pgsql-general, I thought I'd have a go
implementing json_array_elements_text following the same pattern as
json_each_text. The function makes it possible to join elements of a
json array onto a table, for example:

CREATE TABLE object (name TEXT PRIMARY KEY, properties JSON);

INSERT INTO object (name, properties) VALUES
('one', '{}'),
('two', '{"links": ["one"]}'),
('three', '{"links": ["one", "two"]}');

SELECT source.name, target.name
FROM (
SELECT *, json_array_elements_text(properties->'links')::text AS
link_to FROM object
) AS source
JOIN object target ON source.link_to = target.name;


My particular use case has uuid keys for object, which are difficult
to cast from json.

Laurence

---
 doc/src/sgml/func.sgml   | 22 
 src/backend/utils/adt/jsonfuncs.c| 67 +---
 src/include/catalog/pg_proc.h|  2 ++
 src/include/utils/json.h |  1 +
 src/test/regress/expected/json.out   | 34 +++---
 src/test/regress/expected/json_1.out | 34 +++---
 src/test/regress/sql/json.sql|  6 ++--
 7 files changed, 144 insertions(+), 22 deletions(-)
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index c76d357..e7338b5 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -10277,6 +10277,28 @@ table2-mapping
   

  
+  json_array_elements_text
+ 
+ json_array_elements_text(json)
+   
+   SETOF json
+   
+ Expands a JSON array to a set of JSON values. The returned value will be of
+ type text.
+   
+   json_array_elements_text('["foo", "bar"]')
+   
+
+   value
+---
+ foo
+ bar
+
+   
+  
+  
+   
+ 
   json_typeof
  
  json_typeof(json)
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index 90fa447..b8e64f3 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -66,6 +66,9 @@ 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);
 
+/* common worker for json_each* functions */
+static inline Datum elements_worker(PG_FUNCTION_ARGS, bool as_text);
+
 /* semantic action functions for json_array_elements */
 static void elements_object_start(void *state);
 static void elements_array_element_start(void *state, bool isnull);
@@ -157,6 +160,9 @@ typedef struct ElementsState
 	TupleDesc	ret_tdesc;
 	MemoryContext tmp_cxt;
 	char	   *result_start;
+	bool		normalize_results;
+	bool		next_scalar;
+	char	   *normalized_scalar;
 }	ElementsState;
 
 /* state for get_json_object_as_hash */
@@ -1061,7 +1067,7 @@ each_scalar(void *state, char *token, JsonTokenType tokentype)
 }
 
 /*
- * SQL function json_array_elements
+ * SQL function json_array_elements and json_array_elements_text
  *
  * get the elements from a json array
  *
@@ -1070,10 +1076,22 @@ each_scalar(void *state, char *token, JsonTokenType tokentype)
 Datum
 json_array_elements(PG_FUNCTION_ARGS)
 {
+	return elements_worker(fcinfo, false);
+}
+
+Datum
+json_array_elements_text(PG_FUNCTION_ARGS)
+{
+	return elements_worker(fcinfo, true);
+}
+
+static inline Datum
+elements_worker(PG_FUNCTION_ARGS, bool as_text)
+{
 	text	   *json = PG_GETARG_TEXT_P(0);
 
-	/* elements doesn't need any escaped strings, so use false here */
-	JsonLexContext *lex = makeJsonLexContext(json, false);
+	/* elements only needs escaped strings when as_text */
+	JsonLexContext *lex = makeJsonLexContext(json, as_text);
 	JsonSemAction *sem;
 	ReturnSetInfo *rsi;
 	MemoryContext old_cxt;
@@ -1116,6 +1134,9 @@ json_array_elements(PG_FUNCTION_ARGS)
 	sem->array_element_start = elements_array_element_start;
 	sem->array_element_end = elements_array_element_end;
 
+	state->normalize_results = as_text;
+	state->next_scalar = false;
+
 	state->lex = lex;
 	state->tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
 		 "json_array_elements temporary cxt",
@@ -1138,7 +1159,17 @@ elements_array_element_start(void *state, bool isnull)
 
 	/* save a pointer to where the value starts */
 	if (_state->lex->lex_level == 1)
-		_state->result_start = _state->lex->token_start;
+	{
+		/*
+		 * next_scalar will be reset in the array_element_end handler, and
+		 * since we know the value is a scalar there is no danger of it being
+		 * on while recursing down the tree.
+		 */
+		if (_state->normalize_results && _state->lex->token_type == JSON_TOKEN_STRING)
+			_state->next_scalar = true;
+		else
+			_state->result_start = _state->lex->token_start;
+	}
 }
 
 static void
@@ -1150,7 +1181,7 @@ elements_array_element_end(void *state, bool isnull)
 	text	   *val;
 	HeapTuple	tuple;
 	Datum		values[1];
-	static bool nulls[1] = {false};
+	bool nulls[1] = {false};
 
 	/* skip over nested objects */
 	if (_state->lex->