diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out
index 34db7f5..c844d88 100644
*** a/contrib/hstore/expected/hstore.out
--- b/contrib/hstore/expected/hstore.out
*************** select count(*) from testhstore where h
*** 1458,1460 ****
--- 1458,1575 ----
1
(1 row)
+ -- hstore_to_json()
+ select hstore_to_json(''::hstore);
+ hstore_to_json
+ ----------------
+ {}
+ (1 row)
+
+ select hstore_to_json('a=>b'::hstore);
+ hstore_to_json
+ ----------------
+ {"a":"b"}
+ (1 row)
+
+ select hstore_to_json('a=>b');
+ hstore_to_json
+ ----------------
+ {"a":"b"}
+ (1 row)
+
+ select hstore_to_json('a=>b,x=>y'::hstore);
+ hstore_to_json
+ --------------------
+ {"a":"b", "x":"y"}
+ (1 row)
+
+ select hstore_to_json('foo=>bar'::hstore);
+ hstore_to_json
+ ----------------
+ {"foo":"bar"}
+ (1 row)
+
+ select hstore_to_json('foo=>" "'::hstore);
+ hstore_to_json
+ ----------------
+ {"foo":" "}
+ (1 row)
+
+ select hstore_to_json('foo=>"0"'::hstore);
+ hstore_to_json
+ ----------------
+ {"foo":"0"}
+ (1 row)
+
+ select hstore_to_json('foo=>"0 0"'::hstore);
+ hstore_to_json
+ ----------------
+ {"foo":"0 0"}
+ (1 row)
+
+ select hstore_to_json('foo=>"0:0"'::hstore);
+ hstore_to_json
+ ----------------
+ {"foo":"0:0"}
+ (1 row)
+
+ select hstore_to_json('foo' => '0:0');
+ hstore_to_json
+ ----------------
+ {"foo":"0:0"}
+ (1 row)
+
+ select hstore_to_json('aa=>null'::hstore);
+ hstore_to_json
+ ----------------
+ {"aa":null}
+ (1 row)
+
+ select hstore_to_json('aa=>NuLl'::hstore);
+ hstore_to_json
+ ----------------
+ {"aa":null}
+ (1 row)
+
+ select hstore_to_json('aa=>"NuLl"'::hstore);
+ hstore_to_json
+ ----------------
+ {"aa":"NuLl"}
+ (1 row)
+
+ select hstore_to_json('\\=a=>q=w'::hstore);
+ hstore_to_json
+ ----------------
+ {"=a":"q=w"}
+ (1 row)
+
+ select hstore_to_json('"=a"=>q\\=w'::hstore);
+ hstore_to_json
+ ----------------
+ {"=a":"q=w"}
+ (1 row)
+
+ select hstore_to_json('"\\"a"=>q>w'::hstore);
+ hstore_to_json
+ ----------------
+ {"\"a":"q>w"}
+ (1 row)
+
+ select hstore_to_json('\\"a=>q"w'::hstore);
+ hstore_to_json
+ ----------------
+ {"\"a":"q\"w"}
+ (1 row)
+
+ select hstore_to_json(''::hstore);
+ hstore_to_json
+ ----------------
+ {}
+ (1 row)
+
+ select hstore_to_json(' '::hstore);
+ hstore_to_json
+ ----------------
+ {}
+ (1 row)
+
diff --git a/contrib/hstore/hstore.sql.in b/contrib/hstore/hstore.sql.in
index 972557a..d806a84 100644
*** a/contrib/hstore/hstore.sql.in
--- b/contrib/hstore/hstore.sql.in
*************** RETURNS cstring
*** 15,20 ****
--- 15,25 ----
AS 'MODULE_PATHNAME'
LANGUAGE C STRICT IMMUTABLE;
+ CREATE OR REPLACE FUNCTION hstore_to_json(hstore)
+ RETURNS text
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C STRICT IMMUTABLE;
+
CREATE OR REPLACE FUNCTION hstore_recv(internal)
RETURNS hstore
AS 'MODULE_PATHNAME'
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index 31303e4..2bf5416 100644
*** a/contrib/hstore/hstore_io.c
--- b/contrib/hstore/hstore_io.c
***************
*** 12,17 ****
--- 12,18 ----
#include "libpq/pqformat.h"
#include "utils/lsyscache.h"
#include "utils/typcache.h"
+ #include "utils/builtins.h"
#include "hstore.h"
*************** hstore_send(PG_FUNCTION_ARGS)
*** 1208,1210 ****
--- 1209,1291 ----
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
+
+ PG_FUNCTION_INFO_V1(hstore_to_json);
+ Datum hstore_to_json(PG_FUNCTION_ARGS);
+ Datum
+ hstore_to_json(PG_FUNCTION_ARGS)
+ {
+ HStore *in = PG_GETARG_HS(0);
+ int buflen,
+ i;
+ int count = HS_COUNT(in);
+ char *out,
+ *ptr;
+ char *base = STRPTR(in);
+ HEntry *entries = ARRPTR(in);
+
+ if (count == 0)
+ {
+ out = ptr = palloc(3);
+ *ptr++ = '{';
+ *ptr++ = '}';
+ *ptr = '\0';
+ PG_RETURN_CSTRING(cstring_to_text(out));
+ }
+
+ buflen = 0;
+
+ /*
+ * this loop overestimates due to pessimistic assumptions about
+ * escaping, so very large hstore values can't be output. this
+ * could be fixed, but many other data types probably have the
+ * same issue. This replaced code that used the original varlena
+ * size for calculations, which was wrong in some subtle ways.
+ */
+
+ /* include { and } */
+ buflen += 2;
+ for (i = 0; i < count; i++)
+ {
+ /* include "" and => and comma-space */
+ buflen += 6 + 1 * HS_KEYLEN(entries,i);
+ /* include "" only if nonnull */
+ buflen += 2 + (HS_VALISNULL(entries,i)
+ ? 2
+ : 2 * HS_VALLEN(entries,i));
+ }
+
+ out = ptr = palloc(buflen);
+
+ *ptr++ = '{';
+ for (i = 0; i < count; i++)
+ {
+ *ptr++ = '"';
+ ptr = cpw(ptr, HS_KEY(entries,base,i), HS_KEYLEN(entries,i));
+ *ptr++ = '"';
+ *ptr++ = ':';
+ if (HS_VALISNULL(entries,i))
+ {
+ *ptr++ = 'n';
+ *ptr++ = 'u';
+ *ptr++ = 'l';
+ *ptr++ = 'l';
+ }
+ else
+ {
+ *ptr++ = '"';
+ ptr = cpw(ptr, HS_VAL(entries,base,i), HS_VALLEN(entries,i));
+ *ptr++ = '"';
+ }
+
+ if (i + 1 != count)
+ {
+ *ptr++ = ',';
+ *ptr++ = ' ';
+ }
+ }
+ *ptr++ = '}';
+ *ptr = '\0';
+
+ PG_RETURN_TEXT_P(cstring_to_text(out));
+ }
diff --git a/contrib/hstore/sql/hstore.sql b/contrib/hstore/sql/hstore.sql
index a88ff1d..073c9e3 100644
*** a/contrib/hstore/sql/hstore.sql
--- b/contrib/hstore/sql/hstore.sql
*************** set enable_seqscan=off;
*** 336,338 ****
--- 336,361 ----
select count(*) from testhstore where h #># 'p=>1';
select count(*) from testhstore where h = 'pos=>98, line=>371, node=>CBA, indexed=>t';
+
+ -- hstore_to_json()
+ select hstore_to_json(''::hstore);
+ select hstore_to_json('a=>b'::hstore);
+ select hstore_to_json('a=>b');
+ select hstore_to_json('a=>b,x=>y'::hstore);
+ select hstore_to_json('foo=>bar'::hstore);
+ select hstore_to_json('foo=>" "'::hstore);
+ select hstore_to_json('foo=>"0"'::hstore);
+ select hstore_to_json('foo=>"0 0"'::hstore);
+ select hstore_to_json('foo=>"0:0"'::hstore);
+ select hstore_to_json('foo' => '0:0');
+
+ select hstore_to_json('aa=>null'::hstore);
+ select hstore_to_json('aa=>NuLl'::hstore);
+ select hstore_to_json('aa=>"NuLl"'::hstore);
+
+ select hstore_to_json('\\=a=>q=w'::hstore);
+ select hstore_to_json('"=a"=>q\\=w'::hstore);
+ select hstore_to_json('"\\"a"=>q>w'::hstore);
+ select hstore_to_json('\\"a=>q"w'::hstore);
+ select hstore_to_json(''::hstore);
+ select hstore_to_json(' '::hstore);
diff --git a/doc/src/sgml/hstore.sgml b/doc/src/sgml/hstore.sgml
index c7a9d92..8378f8f 100644
*** a/doc/src/sgml/hstore.sgml
--- b/doc/src/sgml/hstore.sgml
*************** b
*** 322,327 ****
--- 322,335 ----
+ hstore_to_json(hstore)
+ text
+ Convert hstore> to text in JSON format
+ hstore_to_json('a=>1,b=>2')
+ {"a":"1","b":"2"}
+
+
+
each(hstore)
setof(key text, value text)
get hstore>'s keys and values as a set