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 ----
       </row>
  
       <row>
+       <entry><function>hstore_to_json(hstore)</function></entry>
+       <entry><type>text</type></entry>
+       <entry>Convert <type>hstore</> to text in JSON format</entry>
+       <entry><literal>hstore_to_json('a=&gt;1,b=&gt;2')</literal></entry>
+       <entry><literal>{"a":"1","b":"2"}</literal></entry>
+      </row>
+ 
+      <row>
        <entry><function>each(hstore)</function></entry>
        <entry><type>setof(key text, value text)</type></entry>
        <entry>get <type>hstore</>'s keys and values as a set</entry>
