From 5b71a10a09d5218e505ff34b1eebe4bf19694159 Mon Sep 17 00:00:00 2001 From: theirix Date: Mon, 3 Sep 2012 16:04:10 +0400 Subject: [PATCH] Added json_object_to_string to build a json string --- expected/postgre-json-functions.out | 14 +++++++++++- postgre-json-functions--1.0.sql | 3 +++ postgre-json-functions.c | 34 ++++++++++++++++++++++++++--- sql/postgre-json-functions.sql | 11 +++++++++- 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/expected/postgre-json-functions.out b/expected/postgre-json-functions.out index 6ced43b..060c000 100644 --- a/expected/postgre-json-functions.out +++ b/expected/postgre-json-functions.out @@ -1,5 +1,5 @@ set client_min_messages to 'error'; -drop extension if exists "postgre-json-functions"; +drop extension if exists "postgre-json-functions" cascade; create extension "postgre-json-functions"; set client_min_messages to 'notice'; \t on @@ -69,5 +69,17 @@ select json_object_get_numeric_array('{"foo":"qq", "bar": [42.4242,43.4343]}', ' -- {"Tue Dec 01 01:23:45 2009","Sat Dec 01 01:23:45 2012"} select json_object_get_timestamp_array('{"foo":"qq", "bar": ["2009-12-01 01:23:45", "2012-12-01 01:23:45"]}', 'bar'); {"Tue Dec 01 01:23:45 2009","Sat Dec 01 01:23:45 2012"} +-- "qq" +select json_object_to_string('{"foo":"qq", "bar": ["baz1", "baz2", "baz3"]}', 'foo'); +"qq" +-- ["baz1","baz2","baz3"] +select json_object_to_string('{"foo":"qq", "bar": ["baz1", "baz2", "baz3"]}', 'bar'); +["baz1","baz2","baz3"] +-- {baz1,baz2,baz3} +select json_array_to_text_array(json_object_to_string('{"foo":"qq", "bar": ["baz1", "baz2", "baz3"]}', 'bar')); +{baz1,baz2,baz3} +-- baz2 +select (json_array_to_text_array(json_object_to_string('{"foo":"qq", "bar": ["baz1", "baz2", "baz3"]}', 'bar')))[2]; +baz2 \t off \pset format aligned diff --git a/postgre-json-functions--1.0.sql b/postgre-json-functions--1.0.sql index dc239fe..709a6f2 100644 --- a/postgre-json-functions--1.0.sql +++ b/postgre-json-functions--1.0.sql @@ -65,6 +65,9 @@ create or replace function json_object_get_numeric_array(text, text) returns num create or replace function json_object_get_timestamp_array(text, text) returns timestamp without time zone[] as 'MODULE_PATHNAME' language C immutable strict; +-- JSON builder +create or replace function json_object_to_string(text, text) returns text + as 'MODULE_PATHNAME' language C immutable strict; -- GIN support diff --git a/postgre-json-functions.c b/postgre-json-functions.c index 9aec014..4ff3f18 100644 --- a/postgre-json-functions.c +++ b/postgre-json-functions.c @@ -54,6 +54,9 @@ PG_MODULE_MAGIC; /* TODO a little hackish format string */ #define NUMERIC_FMT "99999999999999999999999999999999999999.99999999999999999999999999999999999999" +/* Choosen to not override with any of cJSON types */ +#define CJSON_TYPE_ANY 99 + /* * Internal functions declarations */ @@ -88,6 +91,8 @@ bool extract_bigint_array(cJSON *elem, DatumPtr result); bool extract_numeric_array(cJSON *elem, DatumPtr result); bool extract_timestamp_array(cJSON *elem, DatumPtr result); +bool extract_json_to_string(cJSON *elem, DatumPtr result); + /* * Exported functions */ @@ -111,6 +116,8 @@ Datum json_object_get_bigint_array(PG_FUNCTION_ARGS); Datum json_object_get_numeric_array(PG_FUNCTION_ARGS); Datum json_object_get_timestamp_array(PG_FUNCTION_ARGS); +Datum json_object_to_string(PG_FUNCTION_ARGS); + Datum json_gin_compare(PG_FUNCTION_ARGS); Datum json_gin_extract_value(PG_FUNCTION_ARGS); Datum json_gin_extract_query(PG_FUNCTION_ARGS); @@ -146,6 +153,8 @@ PG_FUNCTION_INFO_V1(json_object_get_bigint_array); PG_FUNCTION_INFO_V1(json_object_get_numeric_array); PG_FUNCTION_INFO_V1(json_object_get_timestamp_array); +PG_FUNCTION_INFO_V1(json_object_to_string); + PG_FUNCTION_INFO_V1(json_gin_compare); PG_FUNCTION_INFO_V1(json_gin_extract_value); PG_FUNCTION_INFO_V1(json_gin_extract_query); @@ -225,7 +234,7 @@ Datum json_object_get_generic(text *argJson, text *argKey, int json_type, pextra sel = cJSON_GetObjectItem(root, strKey); if (sel) { - if (match_json_types(json_type, sel->type)) + if (json_type == CJSON_TYPE_ANY || match_json_types(json_type, sel->type)) { if (extractor(sel, &result)) { @@ -311,7 +320,7 @@ Datum json_array_to_array_generic_impl(cJSON *jsonArray, int json_type, Oid elem ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("no childs allowed"))); - if (!match_json_types(json_type, elem->type)) + if (!(json_type == CJSON_TYPE_ANY || match_json_types(json_type, elem->type))) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("expected value of type %s, actual %s at %d position", @@ -482,6 +491,16 @@ bool extract_timestamp_array(cJSON *elem, DatumPtr result) return true; } +bool extract_json_to_string(cJSON *elem, DatumPtr result) +{ + char *pstr; + pstr = cJSON_PrintUnformatted(elem); + *result = PointerGetDatum(cstring_to_text(pstr)); + free(pstr); + return true; +} + + /** * * Exported functions @@ -559,6 +578,7 @@ Datum json_array_to_timestamp_array(PG_FUNCTION_ARGS) /* * Indirect array functions */ + Datum json_object_get_text_array(PG_FUNCTION_ARGS) { return json_object_get_generic_args(fcinfo, cJSON_Array, extract_text_array); @@ -589,6 +609,14 @@ Datum json_object_get_timestamp_array(PG_FUNCTION_ARGS) return json_object_get_generic_args(fcinfo, cJSON_Array, extract_timestamp_array); } +/* Get object by key and converts it back to text + * Used as a proxy call + */ +Datum json_object_to_string(PG_FUNCTION_ARGS) +{ + return json_object_get_generic_args(fcinfo, CJSON_TYPE_ANY, extract_json_to_string); +} + /** * * Operator support @@ -900,7 +928,7 @@ json_gin_extract_query(PG_FUNCTION_ARGS) StrategyNumber strategy = PG_GETARG_UINT16(2); bool **pmatch = (bool**)PG_GETARG_POINTER(3); bool **nullFlags = (bool**)PG_GETARG_POINTER(5); - int32 *searchMode = (int32*)PG_GETARG_POINTER(6); + /* int32 *searchMode = (int32*)PG_GETARG_POINTER(6);*/ ArrayType *queryArray; Datum *keys; diff --git a/sql/postgre-json-functions.sql b/sql/postgre-json-functions.sql index dfa43bc..2cd240d 100644 --- a/sql/postgre-json-functions.sql +++ b/sql/postgre-json-functions.sql @@ -1,5 +1,5 @@ set client_min_messages to 'error'; -drop extension if exists "postgre-json-functions"; +drop extension if exists "postgre-json-functions" cascade; create extension "postgre-json-functions"; set client_min_messages to 'notice'; @@ -54,5 +54,14 @@ select json_object_get_numeric_array('{"foo":"qq", "bar": [42.4242,43.4343]}', ' -- {"Tue Dec 01 01:23:45 2009","Sat Dec 01 01:23:45 2012"} select json_object_get_timestamp_array('{"foo":"qq", "bar": ["2009-12-01 01:23:45", "2012-12-01 01:23:45"]}', 'bar'); +-- "qq" +select json_object_to_string('{"foo":"qq", "bar": ["baz1", "baz2", "baz3"]}', 'foo'); +-- ["baz1","baz2","baz3"] +select json_object_to_string('{"foo":"qq", "bar": ["baz1", "baz2", "baz3"]}', 'bar'); +-- {baz1,baz2,baz3} +select json_array_to_text_array(json_object_to_string('{"foo":"qq", "bar": ["baz1", "baz2", "baz3"]}', 'bar')); +-- baz2 +select (json_array_to_text_array(json_object_to_string('{"foo":"qq", "bar": ["baz1", "baz2", "baz3"]}', 'bar')))[2]; + \t off \pset format aligned