diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 70e21b9..483abb6 100644
*** a/src/backend/utils/adt/Makefile
--- b/src/backend/utils/adt/Makefile
*************** endif
*** 18,24 ****
  OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
  	cash.o char.o date.o datetime.o datum.o domains.o \
  	enum.o float.o format_type.o \
! 	geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o \
  	misc.o nabstime.o name.o numeric.o numutils.o \
  	oid.o oracle_compat.o pseudotypes.o rowtypes.o \
  	regexp.o regproc.o ruleutils.o selfuncs.o \
--- 18,25 ----
  OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
  	cash.o char.o date.o datetime.o datum.o domains.o \
  	enum.o float.o format_type.o \
! 	geo_ops.o geo_selfuncs.o json.o json_parser.o json_scanner.o \
! 	int.o int8.o like.o lockfuncs.o \
  	misc.o nabstime.o name.o numeric.o numutils.o \
  	oid.o oracle_compat.o pseudotypes.o rowtypes.o \
  	regexp.o regproc.o ruleutils.o selfuncs.o \
*************** OBJS = acl.o arrayfuncs.o array_userfunc
*** 33,36 ****
--- 34,62 ----
  
  like.o: like.c like_match.c
  
+ json_parser.o: json_scanner.c
+ 
+ # Latest flex causes warnings in this file.
+ #ifeq ($(GCC),yes)
+ #json_parser.o: CFLAGS += -Wno-error
+ #endif
+ 
+ json_parser.h: json_parser.c ;
+ 
+ json_parser.c: json_parser.y
+ ifdef BISON
+ 	$(BISON) -d $(BISONFLAGS) -o $@ $<
+ else
+ 	@$(missing) bison $< $@
+ endif
+ 
+ json_scanner.c: json_scanner.l
+ ifdef FLEX
+ 	$(FLEX) $(FLEXFLAGS) -o'$@' $<
+ else
+ 	@$(missing) flex $< $@
+ endif
+ 
+ json_parser.o keywords.o parser.o: json_parser.h
+ 
  include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index ...13e5391 .
*** a/src/backend/utils/adt/json.c
--- b/src/backend/utils/adt/json.c
***************
*** 0 ****
--- 1,307 ----
+ /*-------------------------------------------------------------------------
+  *
+  * json.c
+  *	  JSON data type support.
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * $PostgreSQL$
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ 
+ #include "libpq/pqformat.h"
+ #include "utils/builtins.h"
+ #include "utils/json.h"
+ 
+ #include "json_parser.h"
+ #include "json_scanner.h"
+ 
+ static Json *json_parse(const char *str, int len, bool validateOnly);
+ static void json_free(Json *node);
+ static void append_json(StringInfo buf, const Json *node, int indent);
+ static void append_indent(StringInfo buf, int indent);
+ 
+ extern int	json_yyparse(yyscan_t scanner);
+ extern void	json_yyerror(yyscan_t scanner, const char *error);
+ extern void *json_yyalloc(size_t bytes, void *yyscanner);
+ extern void *json_yyrealloc(void *ptr, size_t bytes, void *yyscanner);
+ extern void json_yyfree(void *ptr, void *yyscanner);
+ 
+ /* indent with 4 spaces */
+ #define JSON_INDENT_STRING	"    "
+ 
+ 
+ Datum
+ json_in(PG_FUNCTION_ARGS)
+ {
+ 	char	   *s = PG_GETARG_CSTRING(0);
+ 	jsontype   *json;
+ 
+ 	json = (jsontype *) cstring_to_text(s);
+ 
+ 	/*
+ 	 * Parse the data to check if it is a JSON data.  Assume that
+ 	 * ERROR occurred if parsing failed.
+ 	 */
+ 	json_parse(VARDATA_ANY(json), VARSIZE_ANY_EXHDR(json), true);
+ 
+ 	PG_RETURN_JSON_P(json);
+ }
+ 
+ Datum
+ json_out(PG_FUNCTION_ARGS)
+ {
+ 	/* text and jsontype are binary-compatible */
+ 	return textout(fcinfo);
+ }
+ 
+ Datum
+ json_recv(PG_FUNCTION_ARGS)
+ {
+ 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+ 	jsontype   *result;
+ 	char	   *str;
+ 	int			nbytes;
+ 
+ 	str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
+ 	json_parse(str, nbytes, true);
+ 
+ 	result = (jsontype *) cstring_to_text_with_len(str, nbytes);
+ 	pfree(str);
+ 	PG_RETURN_JSON_P(result);
+ }
+ 
+ Datum
+ json_send(PG_FUNCTION_ARGS)
+ {
+ 	/* text and jsontype are binary-compatible */
+ 	return textsend(fcinfo);
+ }
+ 
+ Datum
+ text_to_json(PG_FUNCTION_ARGS)
+ {
+ 	text	   *t = PG_GETARG_TEXT_PP(0);
+ 
+ 	json_parse(VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t), true);
+ 
+ 	PG_RETURN_JSON_P((jsontype *) t);
+ }
+ 
+ Datum
+ json_to_text(PG_FUNCTION_ARGS)
+ {
+ 	/* text and jsontype are binary-compatible */
+ 	PG_RETURN_DATUM(PG_GETARG_DATUM(0));
+ }
+ 
+ Datum
+ json_pretty(PG_FUNCTION_ARGS)
+ {
+ 	jsontype	   *json = PG_GETARG_JSON_PP(0);
+ 	Json		   *node;
+ 	StringInfoData	buf;
+ 
+ 	node = json_parse(VARDATA_ANY(json), VARSIZE_ANY_EXHDR(json), false);
+ 	initStringInfo(&buf);
+ 	append_json(&buf, node, 0);
+ 	json_free(node);
+ 
+ 	return CStringGetTextDatum(buf.data);
+ }
+ 
+ /*
+  * json_parse -- parse and validate the JSON text.
+  *
+  * Only validates the input when validateOnly is true, or returns JSON
+  * tree on false.
+  */
+ static Json *
+ json_parse(const char *str, int len, bool validateOnly)
+ {
+ 	yyscan_t		scanner;
+ 	char		   *scanbuf;
+ 	JsonParser		parser;
+ 
+ 	scanbuf = (char *) palloc(len + 2);
+ 	memcpy(scanbuf, str, len);
+ 	scanbuf[len] = scanbuf[len + 1] = '\0';
+ 
+ 	/* initialize parser and scanner */
+ 	memset(&parser, 0, sizeof(parser));
+ 	parser.validateOnly = validateOnly;
+ 	if (!validateOnly)
+ 		initStringInfo(&parser.buf);
+ 
+ 	json_yylex_init(&scanner);
+ 	json_yyset_extra(&parser, scanner);
+ 	json_yy_scan_buffer(scanbuf, len + 2, scanner);
+ 
+ 	/* parse the JSON text */
+ 	json_yyparse(scanner);
+ 
+ 	/* cleanup */
+ 	json_yylex_destroy(scanner);
+ 	pfree(scanbuf);
+ 	if (parser.buf.data)
+ 		pfree(parser.buf.data);
+ 
+ 	return parser.json;
+ }
+ 
+ /*
+  * json_free -- free JSON node tree recursively
+  */
+ static void
+ json_free(Json *node)
+ {
+ 	ListCell   *cell;
+ 
+ 	switch (node->type)
+ 	{
+ 	case JSON_NULL:
+ 	case JSON_BOOL:
+ 		break;
+ 	case JSON_NUMBER:
+ 		pfree(node->value.number);
+ 		break;
+ 	case JSON_STRING:
+ 		pfree(node->value.string);
+ 		break;
+ 	case JSON_ARRAY:
+ 		foreach (cell, node->value.array)
+ 		{
+ 			Json *item = (Json *) lfirst(cell);
+ 
+ 			json_free(item);
+ 		}
+ 		list_free(node->value.array);
+ 		break;
+ 	case JSON_OBJECT:
+ 		foreach (cell, node->value.object)
+ 		{
+ 			JsonAttr *attr = (JsonAttr *) lfirst(cell);
+ 
+ 			pfree(attr->key);
+ 			json_free(attr->value);
+ 			pfree(attr);
+ 		}
+ 		list_free(node->value.object);
+ 		break;
+ 	default:
+ 		elog(ERROR, "unexpected json type: %d", node->type);
+ 	}
+ 
+ 	pfree(node);
+ }
+ 
+ /*
+  * append_json -- append JSON node tree to string with indentation
+  */
+ static void
+ append_json(StringInfo buf, const Json *node, int indent)
+ {
+ 	ListCell   *cell;
+ 	bool		sep;
+ 
+ 	switch (node->type)
+ 	{
+ 	case JSON_NULL:
+ 		appendStringInfoString(buf, "null");
+ 		break;
+ 	case JSON_BOOL:
+ 		appendStringInfoString(buf, node->value.boolean ? "true" : "false");
+ 		break;
+ 	case JSON_NUMBER:
+ 		appendStringInfoString(buf, node->value.number);
+ 		break;
+ 	case JSON_STRING:
+ 		appendStringInfoString(buf, node->value.string);
+ 		break;
+ 	case JSON_ARRAY:
+ 		appendStringInfoString(buf, "[\n");
+ 		sep = false;
+ 		foreach (cell, node->value.array)
+ 		{
+ 			const Json *value = (const Json *) lfirst(cell);
+ 
+ 			if (sep)
+ 				appendStringInfoString(buf, ",\n");
+ 			else
+ 				sep = true;
+ 			append_indent(buf, indent + 1);
+ 			append_json(buf, value, indent + 1);
+ 		}
+ 		if (sep)
+ 			appendStringInfoChar(buf, '\n');
+ 		append_indent(buf, indent);
+ 		appendStringInfoChar(buf, ']');
+ 		break;
+ 	case JSON_OBJECT:
+ 		appendStringInfoString(buf, "{\n");
+ 		sep = false;
+ 		foreach (cell, node->value.object)
+ 		{
+ 			const JsonAttr *attr = (const JsonAttr *) lfirst(cell);
+ 			const char *key = attr->key;
+ 			const Json *value = attr->value;
+ 
+ 			if (sep)
+ 				appendStringInfoString(buf, ",\n");
+ 			else
+ 				sep = true;
+ 			append_indent(buf, indent + 1);
+ 			appendStringInfo(buf, "%s: ", key);
+ 			append_json(buf, value, indent + 1);
+ 		}
+ 		if (sep)
+ 			appendStringInfoChar(buf, '\n');
+ 		append_indent(buf, indent);
+ 		appendStringInfoChar(buf, '}');
+ 		break;
+ 	default:
+ 		elog(ERROR, "unexpected json type: %d", node->type);
+ 	}
+ }
+ 
+ static void
+ append_indent(StringInfo buf, int indent)
+ {
+ 	int		i;
+ 	for (i = 0; i < indent; i++)
+ 		appendStringInfoString(buf, JSON_INDENT_STRING);
+ }
+ 
+ void
+ json_yyerror(yyscan_t scanner, const char *error)
+ {
+ 	ereport(ERROR,
+ 			(errcode(ERRCODE_SYNTAX_ERROR),
+ 			 errmsg("syntax error in json: %s", error)));
+ }
+ 
+ void *
+ json_yyalloc(size_t bytes, void *yyscanner)
+ {
+ 	return palloc(bytes);
+ }
+ 
+ void *
+ json_yyrealloc(void *ptr, size_t bytes, void *yyscanner)
+ {
+ 	if (ptr != NULL)
+ 		return repalloc(ptr, bytes);
+ 	else
+ 		return palloc(bytes);
+ }
+ 
+ void
+ json_yyfree(void *ptr, void *yyscanner)
+ {
+ 	if (ptr != NULL)
+ 		pfree(ptr);
+ }
diff --git a/src/backend/utils/adt/json_parser.y b/src/backend/utils/adt/json_parser.y
index ...fb769e2 .
*** a/src/backend/utils/adt/json_parser.y
--- b/src/backend/utils/adt/json_parser.y
***************
*** 0 ****
--- 1,221 ----
+ %{
+ /*-------------------------------------------------------------------------
+  *
+  * json_parser.y
+  *	  Parser for JSON data types.
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * $PostgreSQL$
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ #include "nodes/pg_list.h"
+ #include "utils/json.h"
+ 
+ static Json *makeJsonNode(JsonType type);
+ static Json *makeJsonNull(JsonParser *parser);
+ static Json *makeJsonBool(JsonParser *parser, bool value);
+ static Json *makeJsonNumber(JsonParser *parser, char *value);
+ static Json *makeJsonString(JsonParser *parser, char *value);
+ static Json *makeJsonArray(JsonParser *parser, List *items);
+ static Json *makeJsonObject(JsonParser *parser, List *attrs);
+ static JsonAttr *makeJsonAttr(JsonParser *parser, char *key, Json *value);
+ static List *makeList(JsonParser *parser, void *elem);
+ static List *lconsList(JsonParser *parser, void *elem, List *list);
+ 
+ #include "json_parser.h"
+ #include "json_scanner.h"
+ 
+ #define getParser()		((JsonParser *) json_yyget_extra(scanner))
+ 
+ extern void json_yyerror(yyscan_t, const char *);
+ %}
+ 
+ %defines
+ %expect 0
+ %name-prefix="json_yy"
+ %pure-parser
+ %parse-param	{yyscan_t scanner}
+ %lex-param		{yyscan_t scanner}
+ 
+ %union {
+ 	bool		boolean;
+ 	char	   *number;
+ 	char	   *string;
+ 	Json	   *node;
+ 	JsonAttr   *attr;
+ 	List	   *list;
+ }
+ 
+ %token <string>			T_JSON_STRING
+ %token <number>			T_JSON_NUMBER
+ %token <boolean>		T_JSON_TRUE T_JSON_FALSE
+ %token T_JSON_NULL
+ %token T_JSON_INVALID
+ 
+ %type <number>			number
+ %type <string>			string
+ %type <node>			json value array object 
+ %type <list>			items attrs
+ %type <attr>			attr
+ 
+ %%
+ json:
+ 	  value				{ getParser()->json = $1; }
+ ;
+ 
+ array:
+ 	  '[' ']'			{ $$ = makeJsonArray(getParser(), NIL); }
+ 	| '[' items ']'		{ $$ = makeJsonArray(getParser(), $2);; }
+ ;
+ 
+ items:
+ 	  value				{ $$ = makeList(getParser(), $1); }
+ 	| value ',' items	{ $$ = lconsList(getParser(), $1, $3); }
+ ;
+ 
+ object:
+ 	  '{' '}'			{ $$ = makeJsonObject(getParser(), NIL); }
+ 	| '{' attrs '}'		{ $$ = makeJsonObject(getParser(), $2); }
+ ;
+ 
+ attrs:
+ 	  attr				{ $$ = makeList(getParser(), $1); }
+ 	| attr ',' attrs	{ $$ = lconsList(getParser(), $1, $3); }
+ ;
+ 
+ attr:
+ 	  string ':' value	{ $$ = makeJsonAttr(getParser(), $1, $3); }
+ ;
+ 
+ value:
+ 	  T_JSON_NULL		{ $$ = makeJsonNull(getParser()); }
+ 	| T_JSON_TRUE		{ $$ = makeJsonBool(getParser(), true); }
+ 	| T_JSON_FALSE		{ $$ = makeJsonBool(getParser(), false); }
+ 	| number			{ $$ = makeJsonNumber(getParser(), $1); }
+ 	| string			{ $$ = makeJsonString(getParser(), $1); }
+ 	| array				{ $$ = $1; }
+ 	| object			{ $$ = $1; }
+ ;
+ 
+ number:		T_JSON_NUMBER		{ $$ = $1; };
+ string:		T_JSON_STRING		{ $$ = $1; };
+ 
+ %%
+ static Json *
+ makeJsonNode(JsonType type)
+ {
+ 	Json *node = (Json *) palloc(sizeof(Json));
+ 	node->type = type;
+ 	return node;
+ }
+ 
+ static Json *
+ makeJsonNull(JsonParser *parser)
+ {
+ 	if (parser->validateOnly)
+ 		return NULL;
+ 	else
+ 		return makeJsonNode(JSON_NULL);
+ }
+ 
+ static Json *
+ makeJsonBool(JsonParser *parser, bool value)
+ {
+ 	if (parser->validateOnly)
+ 		return NULL;
+ 	else
+ 	{
+ 		Json *node = makeJsonNode(JSON_BOOL);
+ 		node->value.boolean = value;
+ 		return node;
+ 	}
+ }
+ 
+ static Json *
+ makeJsonNumber(JsonParser *parser, char *value)
+ {
+ 	if (parser->validateOnly)
+ 		return NULL;
+ 	else
+ 	{
+ 		Json *node = makeJsonNode(JSON_NUMBER);
+ 		node->value.number = value;
+ 		return node;
+ 	}
+ }
+ 
+ static Json *
+ makeJsonString(JsonParser *parser, char *value)
+ {
+ 	if (parser->validateOnly)
+ 		return NULL;
+ 	else
+ 	{
+ 		Json *node = makeJsonNode(JSON_STRING);
+ 		node->value.string = value;
+ 		return node;
+ 	}
+ }
+ 
+ static Json *
+ makeJsonArray(JsonParser *parser, List *items)
+ {
+ 	if (parser->validateOnly)
+ 		return NULL;
+ 	else
+ 	{
+ 		Json *node = makeJsonNode(JSON_ARRAY);
+ 		node->value.array = items;
+ 		return node;
+ 	}
+ }
+ 
+ static Json *
+ makeJsonObject(JsonParser *parser, List *attrs)
+ {
+ 	if (parser->validateOnly)
+ 		return NULL;
+ 	else
+ 	{
+ 		Json *node = makeJsonNode(JSON_OBJECT);
+ 		node->value.object = attrs;
+ 		return node;
+ 	}
+ }
+ 
+ static JsonAttr *
+ makeJsonAttr(JsonParser *parser, char *key, Json *value)
+ {
+ 	if (parser->validateOnly)
+ 		return NULL;
+ 	else
+ 	{
+ 		JsonAttr *attr = (JsonAttr *) palloc(sizeof(JsonAttr));
+ 		attr->key = key;
+ 		attr->value = value;
+ 		return attr;
+ 	}
+ }
+ 
+ static List *
+ makeList(JsonParser *parser, void *elem)
+ {
+ 	if (parser->validateOnly)
+ 		return NIL;
+ 	else
+ 		return list_make1(elem);
+ }
+ 
+ static List *
+ lconsList(JsonParser *parser, void *elem, List *list)
+ {
+ 	if (parser->validateOnly)
+ 		return NIL;
+ 	else
+ 		return lcons(elem, list);
+ }
diff --git a/src/backend/utils/adt/json_scanner.l b/src/backend/utils/adt/json_scanner.l
index ...f4ed64f .
*** a/src/backend/utils/adt/json_scanner.l
--- b/src/backend/utils/adt/json_scanner.l
***************
*** 0 ****
--- 1,88 ----
+ %{
+ /*-------------------------------------------------------------------------
+  *
+  * json_snanner.l
+  *	  Lexical scanner for JSON data types.
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * $PostgreSQL$
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ #include "nodes/pg_list.h"
+ #include "utils/json.h"
+ #include "json_parser.h"
+ 
+ #define getParser()			((JsonParser *) json_yyget_extra(yyscanner))
+ %}
+ 
+ %option reentrant
+ %option bison-bridge
+ %option 8bit
+ %option never-interactive
+ %option nodefault
+ %option noinput
+ %option nounput
+ %option noyywrap
+ %option noyyalloc
+ %option noyyrealloc
+ %option noyyfree
+ %option warn
+ %option prefix="json_yy"
+ %option outfile="json_scanner.c" header-file="json_scanner.h"
+ 
+ %x str
+ 
+ %%
+ 	/* Whitespace */
+ [ \t\r\n]
+ 
+ 	/* Symbol */
+ [\[\]\{\}:,] return yytext[0];
+ 
+ 	/* Null */
+ null		{ return T_JSON_NULL; }
+ 
+ 	/* Boolean */
+ true		{ return T_JSON_TRUE; }
+ false		{ return T_JSON_FALSE; }
+ 
+ 	/* Number */
+ 0|-?([1-9][0-9]*(\.[0-9]+)?|0\.[0-9]+)([Ee][+-]?[0-9]+)?	{
+ 		JsonParser *parser = getParser();
+ 		if (!parser->validateOnly)
+ 			yylval->number = pstrdup(yytext);
+ 		return T_JSON_NUMBER;
+ 	}
+ 
+ 	/* String */
+ \"	{
+ 		JsonParser *parser = getParser();
+ 		BEGIN str;
+ 		if (!parser->validateOnly)
+ 			appendStringInfoString(&parser->buf, yytext);
+ 	}
+ <str>([^\"\\[:cntrl:]]+|\\u[0-9A-Fa-f]{4}|\\[\"\\/bfnrt]) {
+ 		JsonParser *parser = getParser();
+ 		if (!parser->validateOnly)
+ 			appendStringInfoString(&parser->buf, yytext);
+ 	}
+ <str>\" {
+ 		JsonParser *parser = getParser();
+ 		if (!parser->validateOnly)
+ 		{
+ 			appendStringInfoString(&parser->buf, yytext);
+ 			yylval->string = pstrdup(parser->buf.data);
+ 			resetStringInfo(&parser->buf);
+ 		}
+ 		BEGIN(INITIAL);
+ 		return T_JSON_STRING;
+ 	}
+ <str>.|\n	{ return T_JSON_INVALID; }	/* unterminated string */
+ 
+ 	/* Invalid */
+ . return T_JSON_INVALID;
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index f53a39a..569dcaa 100644
*** a/src/include/catalog/pg_cast.h
--- b/src/include/catalog/pg_cast.h
*************** DATA(insert (  869	 25  730 a f ));
*** 320,325 ****
--- 320,327 ----
  DATA(insert (	16	 25 2971 a f ));
  DATA(insert (  142	 25    0 a b ));
  DATA(insert (	25	142 2896 e f ));
+ DATA(insert (  321	 25    0 a b ));
+ DATA(insert (	25	321 3830 e f ));
  
  /*
   * Cross-category casts to and from VARCHAR
*************** DATA(insert (  869 1043  730 a f ));
*** 331,336 ****
--- 333,340 ----
  DATA(insert (	16 1043 2971 a f ));
  DATA(insert (  142 1043    0 a b ));
  DATA(insert ( 1043	142 2896 e f ));
+ DATA(insert (  321 1043    0 a b ));
+ DATA(insert ( 1043	321 3830 e f ));
  
  /*
   * Cross-category casts to and from BPCHAR
*************** DATA(insert (  869 1042  730 a f ));
*** 342,347 ****
--- 346,353 ----
  DATA(insert (	16 1042 2971 a f ));
  DATA(insert (  142 1042    0 a b ));
  DATA(insert ( 1042	142 2896 e f ));
+ DATA(insert (  321 1042    0 a b ));
+ DATA(insert ( 1042	321 3830 e f ));
  
  /*
   * Length-coercion functions
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 427f5ea..b3d3da5 100644
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("determine if a string is well for
*** 4457,4462 ****
--- 4457,4478 ----
  DATA(insert OID = 3053 (  xml_is_well_formed_content	 PGNSP PGUID 12 1 0 0 f f f t f i 1 0 16 "25" _null_ _null_ _null_ _null_ xml_is_well_formed_content _null_ _null_ _null_ ));
  DESCR("determine if a string is well formed XML content");
  
+ /* JSON support */
+ DATA(insert OID = 3826 (  json_in			PGNSP PGUID 12 1 0 0 f f f t f i 1 0 321 "2275" _null_ _null_ _null_ _null_ json_in _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3827 (  json_out			PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2275 "321" _null_ _null_ _null_ _null_ json_out _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3828 (  json_recv			PGNSP PGUID 12 1 0 0 f f f t f i 1 0 321 "2281" _null_ _null_ _null_ _null_ json_recv _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3829 (  json_send			PGNSP PGUID 12 1 0 0 f f f t f i 1 0 17 "321" _null_ _null_ _null_ _null_ json_send _null_ _null_ _null_ ));
+ DESCR("I/O");
+ DATA(insert OID = 3830 (  json				PGNSP PGUID 12 1 0 0 f f f t f s 1 0 321 "25" _null_ _null_ _null_ _null_ text_to_json _null_ _null_ _null_ ));
+ DESCR("perform a non-validating parse of a character string to produce a JSON value");
+ DATA(insert OID = 3831 (  text				PGNSP PGUID 12 1 0 0 f f f t f i 1 0 25 "321" _null_ _null_ _null_ _null_ json_to_text _null_ _null_ _null_ ));
+ DESCR("serialize a JSON value to a character string");
+ DATA(insert OID = 3832 (  json_pretty		PGNSP PGUID 12 1 0 0 f f f t f i 1 0 25 "321" _null_ _null_ _null_ _null_ json_pretty _null_ _null_ _null_ ));
+ DESCR("convert a JSON to a human readable text");
+ 
  /* uuid */
  DATA(insert OID = 2952 (  uuid_in		   PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2950 "2275" _null_ _null_ _null_ _null_ uuid_in _null_ _null_ _null_ ));
  DESCR("I/O");
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 05fc974..6b110bf 100644
*** a/src/include/catalog/pg_type.h
--- b/src/include/catalog/pg_type.h
*************** DESCR("storage manager");
*** 354,359 ****
--- 354,364 ----
  
  /* OIDS 300 - 399 */
  
+ DATA(insert OID = 321 ( json	   PGNSP PGUID -1 f b U f t \054 0 0 322 json_in json_out json_recv json_send - - - i x f 0 -1 0 _null_ _null_ ));
+ DESCR("JSON content");
+ #define JSONOID 321
+ DATA(insert OID = 322 ( _json	   PGNSP PGUID -1 f b A f t \054 0 321 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ ));
+ 
  /* OIDS 400 - 499 */
  
  /* OIDS 500 - 599 */
diff --git a/src/include/utils/json.h b/src/include/utils/json.h
index ...952d1bc .
*** a/src/include/utils/json.h
--- b/src/include/utils/json.h
***************
*** 0 ****
--- 1,75 ----
+ /*-------------------------------------------------------------------------
+  *
+  * json.h
+  *	  Declarations for JSON data type support.
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * $PostgreSQL$
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #ifndef JSON_H
+ #define JSON_H
+ 
+ #include "fmgr.h"
+ #include "nodes/execnodes.h"
+ #include "nodes/primnodes.h"
+ 
+ typedef struct varlena jsontype;
+ 
+ #define DatumGetJsonP(X)		((jsontype *) PG_DETOAST_DATUM(X))
+ #define DatumGetJsonPP(X)		((jsontype *) PG_DETOAST_DATUM_PACKED(X))
+ #define JsonPGetDatum(X)		PointerGetDatum(X)
+ 
+ #define PG_GETARG_JSON_P(n)		DatumGetJsonP(PG_GETARG_DATUM(n))
+ #define PG_GETARG_JSON_PP(n)	DatumGetJsonPP(PG_GETARG_DATUM(n))
+ #define PG_RETURN_JSON_P(x)		PG_RETURN_POINTER(x)
+ 
+ extern Datum json_in(PG_FUNCTION_ARGS);
+ extern Datum json_out(PG_FUNCTION_ARGS);
+ extern Datum json_recv(PG_FUNCTION_ARGS);
+ extern Datum json_send(PG_FUNCTION_ARGS);
+ extern Datum text_to_json(PG_FUNCTION_ARGS);
+ extern Datum json_to_text(PG_FUNCTION_ARGS);
+ extern Datum json_pretty(PG_FUNCTION_ARGS);
+ 
+ typedef enum JsonType
+ {
+ 	JSON_NULL,
+ 	JSON_BOOL,
+ 	JSON_NUMBER,
+ 	JSON_STRING,
+ 	JSON_ARRAY,
+ 	JSON_OBJECT
+ } JsonType;
+ 
+ typedef struct Json
+ {
+ 	JsonType	type;
+ 	union
+ 	{
+ 		bool	boolean;
+ 		char   *number;
+ 		char   *string;
+ 		List   *array;		/* a list of Json */
+ 		List   *object;		/* a list of JsonAttr */
+ 	} value;
+ } Json;
+ 
+ typedef struct JsonAttr
+ {
+ 	char	   *key;
+ 	Json	   *value;
+ } JsonAttr;
+ 
+ typedef struct JsonParser
+ {
+ 	Json		   *json;
+ 	StringInfoData	buf;
+ 	bool			validateOnly;
+ } JsonParser;
+ 
+ #endif   /* JSON_H */
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index ...1237714 .
*** a/src/test/regress/expected/json.out
--- b/src/test/regress/expected/json.out
***************
*** 0 ****
--- 1,39 ----
+ CREATE TABLE jsontest (
+     id int,
+     data json
+ );
+ INSERT INTO jsontest VALUES (1, 'null');
+ INSERT INTO jsontest VALUES (2, '{"booleans":[true,false],"null":null}');
+ INSERT INTO jsontest VALUES (3, E'[\n123.456,\n"string",\n{"name":"object"}\n]');
+ INSERT INTO jsontest VALUES (101, 'wrong');
+ ERROR:  syntax error in json: syntax error
+ LINE 1: INSERT INTO jsontest VALUES (101, 'wrong');
+                                           ^
+ INSERT INTO jsontest VALUES (101, '[wrong');
+ ERROR:  syntax error in json: syntax error
+ LINE 1: INSERT INTO jsontest VALUES (101, '[wrong');
+                                           ^
+ INSERT INTO jsontest VALUES (101, '{"wrong":123}}');
+ ERROR:  syntax error in json: syntax error
+ LINE 1: INSERT INTO jsontest VALUES (101, '{"wrong":123}}');
+                                           ^
+ SELECT *, json_pretty(data) FROM jsontest;
+  id |                 data                  |       json_pretty        
+ ----+---------------------------------------+--------------------------
+   1 | null                                  | null
+   2 | {"booleans":[true,false],"null":null} | {                       +
+     |                                       |     "booleans": [       +
+     |                                       |         true,           +
+     |                                       |         false           +
+     |                                       |     ],                  +
+     |                                       |     "null": null        +
+     |                                       | }
+   3 | [                                    +| [                       +
+     | 123.456,                             +|     123.456,            +
+     | "string",                            +|     "string",           +
+     | {"name":"object"}                    +|     {                   +
+     | ]                                     |         "name": "object"+
+     |                                       |     }                   +
+     |                                       | ]
+ (3 rows)
+ 
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 4703d49..ca6ff28 100644
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE c.castfunc = p.oid AND
*** 402,407 ****
--- 402,409 ----
  -- texttoxml(), which does an XML syntax check.
  -- As of 9.1, this finds the cast from pg_node_tree to text, which we
  -- intentionally do not provide a reverse pathway for.
+ -- Also, this finds the casts from json to text, varchar, and bpchar,
+ -- because of the same reason as xml.
  SELECT castsource::regtype, casttarget::regtype, castfunc, castcontext
  FROM pg_cast c
  WHERE c.castmethod = 'b' AND
*************** WHERE c.castmethod = 'b' AND
*** 416,424 ****
   pg_node_tree      | text              |        0 | i
   cidr              | inet              |        0 | i
   xml               | text              |        0 | a
   xml               | character varying |        0 | a
   xml               | character         |        0 | a
! (7 rows)
  
  -- **************** pg_operator ****************
  -- Look for illegal values in pg_operator fields.
--- 418,429 ----
   pg_node_tree      | text              |        0 | i
   cidr              | inet              |        0 | i
   xml               | text              |        0 | a
+  json              | text              |        0 | a
   xml               | character varying |        0 | a
+  json              | character varying |        0 | a
   xml               | character         |        0 | a
!  json              | character         |        0 | a
! (10 rows)
  
  -- **************** pg_operator ****************
  -- Look for illegal values in pg_operator fields.
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 191d1fe..e056bd2 100644
*** a/src/test/regress/parallel_schedule
--- b/src/test/regress/parallel_schedule
*************** test: select_views portals_p2 foreign_ke
*** 91,97 ****
  # NB: temp.sql does a reconnect which transiently uses 2 connections,
  # so keep this parallel group to at most 19 tests
  # ----------
! test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml
  
  # run stats by itself because its delay may be insufficient under heavy load
  test: stats
--- 91,97 ----
  # NB: temp.sql does a reconnect which transiently uses 2 connections,
  # so keep this parallel group to at most 19 tests
  # ----------
! test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism rowtypes returning largeobject with xml json
  
  # run stats by itself because its delay may be insufficient under heavy load
  test: stats
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 80a9881..3965bef 100644
*** a/src/test/regress/serial_schedule
--- b/src/test/regress/serial_schedule
*************** test: returning
*** 123,126 ****
--- 123,127 ----
  test: largeobject
  test: with
  test: xml
+ text: json
  test: stats
diff --git a/src/test/regress/sql/json.sql b/src/test/regress/sql/json.sql
index ...76a1d06 .
*** a/src/test/regress/sql/json.sql
--- b/src/test/regress/sql/json.sql
***************
*** 0 ****
--- 1,13 ----
+ CREATE TABLE jsontest (
+     id int,
+     data json
+ );
+ 
+ INSERT INTO jsontest VALUES (1, 'null');
+ INSERT INTO jsontest VALUES (2, '{"booleans":[true,false],"null":null}');
+ INSERT INTO jsontest VALUES (3, E'[\n123.456,\n"string",\n{"name":"object"}\n]');
+ INSERT INTO jsontest VALUES (101, 'wrong');
+ INSERT INTO jsontest VALUES (101, '[wrong');
+ INSERT INTO jsontest VALUES (101, '{"wrong":123}}');
+ 
+ SELECT *, json_pretty(data) FROM jsontest;
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 0d084a1..fb71bb2 100644
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE c.castfunc = p.oid AND
*** 320,325 ****
--- 320,327 ----
  
  -- As of 9.1, this finds the cast from pg_node_tree to text, which we
  -- intentionally do not provide a reverse pathway for.
+ -- Also, this finds the casts from json to text, varchar, and bpchar,
+ -- because of the same reason as xml.
  
  SELECT castsource::regtype, casttarget::regtype, castfunc, castcontext
  FROM pg_cast c