summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoey Adams2010-06-09 03:23:34 +0000
committerJoey Adams2010-06-09 03:23:34 +0000
commit27d164bc9af93c9fe87649367248b7b794d1aacd (patch)
tree4d40829424afb05fce7a2e8d3ebaf374a814cf45
parent88262d4c8b922673e56e3dc9452dd29b85ace641 (diff)
Implemented from_json (for basic types, just like to_json) along with testcases.
-rw-r--r--contrib/json/expected/json.out170
-rw-r--r--contrib/json/json.sql.in5
-rw-r--r--contrib/json/json_io.c48
-rw-r--r--contrib/json/out21
-rw-r--r--contrib/json/out.diff433
-rw-r--r--contrib/json/polymorphism-difficulty-blurb16
-rw-r--r--contrib/json/sql/json.sql58
-rw-r--r--contrib/json/trash144
8 files changed, 264 insertions, 631 deletions
diff --git a/contrib/json/expected/json.out b/contrib/json/expected/json.out
index a3828d4..ecf4105 100644
--- a/contrib/json/expected/json.out
+++ b/contrib/json/expected/json.out
@@ -179,7 +179,7 @@ SELECT json_type(j) FROM testjson;
object
(8 rows)
--- null
+-- to_json: null
SELECT to_json(NULL);
ERROR: could not determine polymorphic type because input has type "unknown"
SELECT to_json(NULL::INT);
@@ -204,7 +204,7 @@ SELECT json_type(to_json(NULL::VOID));
ERROR: to_json: cannot convert void to JSON
SELECT json_type(to_json(NULL::MONEY));
ERROR: to_json: cannot convert money to JSON
--- string
+-- to_json: string
SELECT to_json('');
ERROR: could not determine polymorphic type because input has type "unknown"
SELECT json_type(to_json(''));
@@ -321,7 +321,7 @@ SELECT json_type(to_json('hello world!'::CHAR(11)));
string
(1 row)
--- number
+-- to_json: number
SELECT to_json(12345);
to_json
---------
@@ -372,7 +372,7 @@ SELECT json_type(to_json(1234567890123456789012345678901234567890123456789012345
SELECT to_json('100'::MONEY);
ERROR: to_json: cannot convert money to JSON
--- bool
+-- to_json: bool
SELECT to_json(TRUE);
to_json
---------
@@ -433,11 +433,169 @@ SELECT to_json(FALSE::TEXT)::TEXT = '"' || FALSE || '"';
t
(1 row)
--- array
+-- to_json: array
SELECT to_json(ARRAY[1,2,3]);
ERROR: to_json does not support conversion from arrays yet
--- Invalid types
+-- to_json: invalid types
SELECT to_json(row(1,2));
ERROR: to_json: cannot convert record to JSON
SELECT to_json('127.0.0.1'::INET);
ERROR: to_json: cannot convert inet to JSON
+-- from_json: null
+SELECT from_json(null);
+ from_json
+-----------
+
+(1 row)
+
+SELECT from_json(NULL::TEXT);
+ERROR: function from_json(text) does not exist
+LINE 1: SELECT from_json(NULL::TEXT);
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+SELECT from_json(NULL::JSON);
+ from_json
+-----------
+
+(1 row)
+
+-- from_json: string
+SELECT from_json('"valid string"');
+ from_json
+--------------
+ valid string
+(1 row)
+
+SELECT from_json($$ "hello\nworld" $$);
+ from_json
+-----------
+ hello +
+ world
+(1 row)
+
+-- from_json: number
+SELECT from_json('123');
+ from_json
+-----------
+ 123
+(1 row)
+
+SELECT from_json('123')::INT;
+ from_json
+-----------
+ 123
+(1 row)
+
+SELECT from_json('123.456')::INT;
+ERROR: invalid input syntax for integer: "123.456"
+SELECT from_json('123.456')::FLOAT;
+ from_json
+-----------
+ 123.456
+(1 row)
+
+SELECT from_json('123e-38');
+ from_json
+-----------
+ 123e-38
+(1 row)
+
+SELECT from_json('123e-38')::FLOAT;
+ from_json
+-----------
+ 1.23e-36
+(1 row)
+
+SELECT from_json('1.23e-38')::FLOAT;
+ from_json
+-----------
+ 1.23e-38
+(1 row)
+
+SELECT from_json('1.23e-38');
+ from_json
+-----------
+ 1.23e-38
+(1 row)
+
+SELECT from_json('1.23e-38')::NUMERIC;
+ from_json
+--------------------------------------------
+ 0.0000000000000000000000000000000000000123
+(1 row)
+
+-- from_json: bool
+SELECT from_json('true')::JSON;
+ from_json
+-----------
+ true
+(1 row)
+
+SELECT from_json('true');
+ from_json
+-----------
+ true
+(1 row)
+
+SELECT from_json('true')::BOOLEAN;
+ from_json
+-----------
+ t
+(1 row)
+
+SELECT from_json('true')::BOOLEAN::JSON;
+ERROR: invalid JSON content
+SELECT from_json('true')::BOOLEAN::TEXT::JSON;
+ from_json
+-----------
+ true
+(1 row)
+
+SELECT from_json('false')::BOOLEAN::TEXT::JSON;
+ from_json
+-----------
+ false
+(1 row)
+
+SELECT from_json('false');
+ from_json
+-----------
+ false
+(1 row)
+
+SELECT from_json('f');
+ERROR: invalid JSON content
+LINE 1: SELECT from_json('f');
+ ^
+SELECT from_json('t');
+ERROR: invalid JSON content
+LINE 1: SELECT from_json('t');
+ ^
+SELECT from_json('f'::BOOLEAN::TEXT);
+ERROR: function from_json(text) does not exist
+LINE 1: SELECT from_json('f'::BOOLEAN::TEXT);
+ ^
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
+SELECT from_json('f'::BOOLEAN::TEXT::JSON);
+ from_json
+-----------
+ false
+(1 row)
+
+SELECT from_json('t'::BOOLEAN::TEXT::JSON);
+ from_json
+-----------
+ true
+(1 row)
+
+-- from_json: object
+SELECT from_json('{"key": "value"}');
+ERROR: from_json does not support conversion from objects yet
+-- from_json: array
+SELECT from_json('[1,2,3]');
+ERROR: from_json does not support conversion from arrays yet
+-- from_json: invalid
+SELECT from_json('invalid');
+ERROR: invalid JSON content
+LINE 1: SELECT from_json('invalid');
+ ^
diff --git a/contrib/json/json.sql.in b/contrib/json/json.sql.in
index a2426e8..5e4dcf3 100644
--- a/contrib/json/json.sql.in
+++ b/contrib/json/json.sql.in
@@ -44,6 +44,11 @@ RETURNS json_type_t
AS 'MODULE_PATHNAME','json_get_type'
LANGUAGE C STRICT IMMUTABLE;
+CREATE OR REPLACE FUNCTION from_json(json)
+RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
CREATE OR REPLACE FUNCTION to_json(anyelement)
RETURNS json
AS 'MODULE_PATHNAME'
diff --git a/contrib/json/json_io.c b/contrib/json/json_io.c
index 53c8c6f..e3fe080 100644
--- a/contrib/json/json_io.c
+++ b/contrib/json/json_io.c
@@ -80,15 +80,13 @@ typedef struct {
bool typispreferred;
} TypeInfo;
-static void
-initTypeInfo(TypeInfo *d, MemoryContext mcxt)
+static void initTypeInfo(TypeInfo *d, MemoryContext mcxt)
{
d->mcxt = mcxt;
d->not_set = true;
}
-static void
-getTypeInfo(TypeInfo *d, Oid type, IOFuncSelector which_func)
+static void getTypeInfo(TypeInfo *d, Oid type, IOFuncSelector which_func)
{
if (d->not_set || d->type != type || d->which_func != which_func) {
get_type_io_data(type, which_func,
@@ -141,6 +139,48 @@ decide_json_type(Oid type, char category)
}
}
+PG_FUNCTION_INFO_V1(from_json);
+Datum from_json(PG_FUNCTION_ARGS);
+Datum
+from_json(PG_FUNCTION_ARGS)
+{
+ jsontype *vardata = PG_GETARG_JSON_P(0);
+ text *vardata_out = NULL;
+ char *cstring = text_to_cstring((text*) vardata);
+ const char *cstring_out = NULL;
+ size_t len;
+ json_node *json = json_decode(cstring);
+
+ if (json == NULL)
+ elog(ERROR, "from_json: JSON content was corrupted");
+
+ switch (json->type) {
+ case JSON_NULL:
+ PG_RETURN_NULL();
+ case JSON_STRING:
+ cstring_out = json_get_string(json, &len);
+ if (strlen(cstring_out) != len)
+ elog(ERROR, "from_json: null terminator occurred in a JSON string; can't convert to TEXT"/* (use from_json_as_bytea instead)*/);
+ break;
+ case JSON_NUMBER:
+ cstring_out = json_get_number(json);
+ break;
+ case JSON_BOOL:
+ cstring_out = json_get_bool(json) ? "true" : "false";
+ break;
+ case JSON_OBJECT:
+ elog(ERROR, "from_json does not support conversion from objects yet");
+ case JSON_ARRAY:
+ elog(ERROR, "from_json does not support conversion from arrays yet");
+ break;
+ default:
+ Assert(false);
+ }
+
+ vardata_out = cstring_to_text(cstring_out);
+
+ PG_RETURN_TEXT_P(vardata_out);
+}
PG_FUNCTION_INFO_V1(to_json);
Datum to_json(PG_FUNCTION_ARGS);
diff --git a/contrib/json/out b/contrib/json/out
deleted file mode 100644
index 60eb492..0000000
--- a/contrib/json/out
+++ /dev/null
@@ -1,21 +0,0 @@
- typname | typnamespace | typowner | typlen | typbyval | typtype | typcategory | typispreferred | typisdefined | typdelim | typrelid | typelem | typarray | typinput | typoutput | typreceive | typsend | typmodin | typmodout | typanalyze | typalign | typstorage | typnotnull | typbasetype | typtypmod | typndims | typdefaultbin | typdefault
------------------+--------------+----------+--------+----------+---------+-------------+----------------+--------------+----------+----------+---------+----------+-----------------+------------------+-------------------+-------------------+-----------------+------------------+------------+----------+------------+------------+-------------+-----------+----------+---------------+------------
- int8 | 11 | 10 | 8 | f | b | N | f | t | , | 0 | 0 | 1016 | int8in | int8out | int8recv | int8send | - | - | - | d | p | f | 0 | -1 | 0 | |
- int2 | 11 | 10 | 2 | t | b | N | f | t | , | 0 | 0 | 1005 | int2in | int2out | int2recv | int2send | - | - | - | s | p | f | 0 | -1 | 0 | |
- int4 | 11 | 10 | 4 | t | b | N | f | t | , | 0 | 0 | 1007 | int4in | int4out | int4recv | int4send | - | - | - | i | p | f | 0 | -1 | 0 | |
- regproc | 11 | 10 | 4 | t | b | N | f | t | , | 0 | 0 | 1008 | regprocin | regprocout | regprocrecv | regprocsend | - | - | - | i | p | f | 0 | -1 | 0 | |
- oid | 11 | 10 | 4 | t | b | N | t | t | , | 0 | 0 | 1028 | oidin | oidout | oidrecv | oidsend | - | - | - | i | p | f | 0 | -1 | 0 | |
- float4 | 11 | 10 | 4 | t | b | N | f | t | , | 0 | 0 | 1021 | float4in | float4out | float4recv | float4send | - | - | - | i | p | f | 0 | -1 | 0 | |
- float8 | 11 | 10 | 8 | f | b | N | t | t | , | 0 | 0 | 1022 | float8in | float8out | float8recv | float8send | - | - | - | d | p | f | 0 | -1 | 0 | |
- money | 11 | 10 | 8 | f | b | N | f | t | , | 0 | 0 | 791 | cash_in | cash_out | cash_recv | cash_send | - | - | - | d | p | f | 0 | -1 | 0 | |
- numeric | 11 | 10 | -1 | f | b | N | f | t | , | 0 | 0 | 1231 | numeric_in | numeric_out | numeric_recv | numeric_send | numerictypmodin | numerictypmodout | - | i | m | f | 0 | -1 | 0 | |
- regprocedure | 11 | 10 | 4 | t | b | N | f | t | , | 0 | 0 | 2207 | regprocedurein | regprocedureout | regprocedurerecv | regproceduresend | - | - | - | i | p | f | 0 | -1 | 0 | |
- regoper | 11 | 10 | 4 | t | b | N | f | t | , | 0 | 0 | 2208 | regoperin | regoperout | regoperrecv | regopersend | - | - | - | i | p | f | 0 | -1 | 0 | |
- regoperator | 11 | 10 | 4 | t | b | N | f | t | , | 0 | 0 | 2209 | regoperatorin | regoperatorout | regoperatorrecv | regoperatorsend | - | - | - | i | p | f | 0 | -1 | 0 | |
- regclass | 11 | 10 | 4 | t | b | N | f | t | , | 0 | 0 | 2210 | regclassin | regclassout | regclassrecv | regclasssend | - | - | - | i | p | f | 0 | -1 | 0 | |
- regtype | 11 | 10 | 4 | t | b | N | f | t | , | 0 | 0 | 2211 | regtypein | regtypeout | regtyperecv | regtypesend | - | - | - | i | p | f | 0 | -1 | 0 | |
- regconfig | 11 | 10 | 4 | t | b | N | f | t | , | 0 | 0 | 3735 | regconfigin | regconfigout | regconfigrecv | regconfigsend | - | - | - | i | p | f | 0 | -1 | 0 | |
- regdictionary | 11 | 10 | 4 | t | b | N | f | t | , | 0 | 0 | 3770 | regdictionaryin | regdictionaryout | regdictionaryrecv | regdictionarysend | - | - | - | i | p | f | 0 | -1 | 0 | |
- cardinal_number | 11342 | 10 | 4 | t | d | N | f | t | , | 0 | 0 | 0 | domain_in | int4out | domain_recv | int4send | - | - | - | i | p | f | 23 | -1 | 0 | |
-(17 rows)
-
diff --git a/contrib/json/out.diff b/contrib/json/out.diff
deleted file mode 100644
index ec2e1d2..0000000
--- a/contrib/json/out.diff
+++ /dev/null
@@ -1,433 +0,0 @@
-diff --git a/contrib/json/out.diff b/contrib/json/out.diff
-index 7a31cfd..e69de29 100644
---- a/contrib/json/out.diff
-+++ b/contrib/json/out.diff
-@@ -1,428 +0,0 @@
--diff --git a/contrib/json/Makefile b/contrib/json/Makefile
--index d7a1e48..2b5cc71 100644
----- a/contrib/json/Makefile
--+++ b/contrib/json/Makefile
--@@ -3,7 +3,7 @@ top_builddir = ../..
-- include $(top_builddir)/src/Makefile.global
--
-- MODULE_big = json
---OBJS = json.o json_io.o json_ops.o
--+OBJS = json.o json_io.o json_op.o
--
-- DATA_built = json.sql
-- DATA = uninstall_json.sql
--diff --git a/contrib/json/expected/json.out b/contrib/json/expected/json.out
--index e720e23..a3828d4 100644
----- a/contrib/json/expected/json.out
--+++ b/contrib/json/expected/json.out
--@@ -179,3 +179,265 @@ SELECT json_type(j) FROM testjson;
-- object
-- (8 rows)
--
--+-- null
--+SELECT to_json(NULL);
--+ERROR: could not determine polymorphic type because input has type "unknown"
--+SELECT to_json(NULL::INT);
--+ to_json
--+---------
--+ null
--+(1 row)
--+
--+SELECT to_json(NULL::VOID);
--+ERROR: to_json: cannot convert void to JSON
--+SELECT to_json(NULL::MONEY);
--+ERROR: to_json: cannot convert money to JSON
--+SELECT json_type(to_json(NULL));
--+ERROR: could not determine polymorphic type because input has type "unknown"
--+SELECT json_type(to_json(NULL::INT));
--+ json_type
--+-----------
--+ null
--+(1 row)
--+
--+SELECT json_type(to_json(NULL::VOID));
--+ERROR: to_json: cannot convert void to JSON
--+SELECT json_type(to_json(NULL::MONEY));
--+ERROR: to_json: cannot convert money to JSON
--+-- string
--+SELECT to_json('');
--+ERROR: could not determine polymorphic type because input has type "unknown"
--+SELECT json_type(to_json(''));
--+ERROR: could not determine polymorphic type because input has type "unknown"
--+SELECT to_json('string');
--+ERROR: could not determine polymorphic type because input has type "unknown"
--+SELECT json_type(to_json('string'));
--+ERROR: could not determine polymorphic type because input has type "unknown"
--+SELECT to_json('string'::VARCHAR);
--+ to_json
--+----------
--+ "string"
--+(1 row)
--+
--+SELECT json_type(to_json('string'::VARCHAR));
--+ json_type
--+-----------
--+ string
--+(1 row)
--+
--+SELECT to_json('string'::VARCHAR(3));
--+ to_json
--+---------
--+ "str"
--+(1 row)
--+
--+SELECT json_type(to_json('string'::VARCHAR(3)));
--+ json_type
--+-----------
--+ string
--+(1 row)
--+
--+SELECT to_json('{1,2,3}'::TEXT);
--+ to_json
--+-----------
--+ "{1,2,3}"
--+(1 row)
--+
--+SELECT json_type(to_json('{1,2,3}'::TEXT));
--+ json_type
--+-----------
--+ string
--+(1 row)
--+
--+SELECT to_json('"doubly-encoded"'::JSON);
--+ to_json
--+----------------------
--+ "\"doubly-encoded\""
--+(1 row)
--+
--+SELECT json_type(to_json('"doubly-encoded"'::JSON));
--+ json_type
--+-----------
--+ string
--+(1 row)
--+
--+SELECT to_json('"nested quotes"'::TEXT);
--+ to_json
--+---------------------
--+ "\"nested quotes\""
--+(1 row)
--+
--+SELECT json_type(to_json('"nested quotes"'::TEXT));
--+ json_type
--+-----------
--+ string
--+(1 row)
--+
--+SELECT to_json('"nested quotes"'::TEXT)::TEXT::JSON;
--+ to_json
--+---------------------
--+ "\"nested quotes\""
--+(1 row)
--+
--+SELECT json_type(to_json('"nested quotes"'::TEXT)::TEXT::JSON);
--+ json_type
--+-----------
--+ string
--+(1 row)
--+
--+SELECT to_json('h'::CHAR);
--+ to_json
--+---------
--+ "h"
--+(1 row)
--+
--+SELECT json_type(to_json('h'::CHAR));
--+ json_type
--+-----------
--+ string
--+(1 row)
--+
--+SELECT to_json('hello world'::CHAR);
--+ to_json
--+---------
--+ "h"
--+(1 row)
--+
--+SELECT json_type(to_json('hello world'::CHAR));
--+ json_type
--+-----------
--+ string
--+(1 row)
--+
--+SELECT to_json('hello world!'::CHAR(11));
--+ to_json
--+---------------
--+ "hello world"
--+(1 row)
--+
--+SELECT json_type(to_json('hello world!'::CHAR(11)));
--+ json_type
--+-----------
--+ string
--+(1 row)
--+
--+-- number
--+SELECT to_json(12345);
--+ to_json
--+---------
--+ 12345
--+(1 row)
--+
--+SELECT to_json(12345.678);
--+ to_json
--+-----------
--+ 12345.678
--+(1 row)
--+
--+SELECT json_type(to_json(12345));
--+ json_type
--+-----------
--+ number
--+(1 row)
--+
--+SELECT json_type(to_json(12345.678));
--+ json_type
--+-----------
--+ number
--+(1 row)
--+
--+SELECT to_json(+1.23e100::FLOAT);
--+ to_json
--+-----------
--+ 1.23e+100
--+(1 row)
--+
--+SELECT to_json('+1.23e100'::FLOAT);
--+ to_json
--+-----------
--+ 1.23e+100
--+(1 row)
--+
--+SELECT to_json(123456789012345678901234567890123456789012345678901234567890.123456789012345678901234567890123456789012345678901234567890);
--+ to_json
--+---------------------------------------------------------------------------------------------------------------------------
--+ 123456789012345678901234567890123456789012345678901234567890.123456789012345678901234567890123456789012345678901234567890
--+(1 row)
--+
--+SELECT json_type(to_json(123456789012345678901234567890123456789012345678901234567890.123456789012345678901234567890123456789012345678901234567890));
--+ json_type
--+-----------
--+ number
--+(1 row)
--+
--+SELECT to_json('100'::MONEY);
--+ERROR: to_json: cannot convert money to JSON
--+-- bool
--+SELECT to_json(TRUE);
--+ to_json
--+---------
--+ true
--+(1 row)
--+
--+SELECT to_json(FALSE);
--+ to_json
--+---------
--+ false
--+(1 row)
--+
--+SELECT to_json(1=1);
--+ to_json
--+---------
--+ true
--+(1 row)
--+
--+SELECT to_json(1=2);
--+ to_json
--+---------
--+ false
--+(1 row)
--+
--+SELECT json_type(to_json(TRUE));
--+ json_type
--+-----------
--+ bool
--+(1 row)
--+
--+SELECT json_type(to_json(FALSE));
--+ json_type
--+-----------
--+ bool
--+(1 row)
--+
--+SELECT json_type(to_json(1=1));
--+ json_type
--+-----------
--+ bool
--+(1 row)
--+
--+SELECT json_type(to_json(1=2));
--+ json_type
--+-----------
--+ bool
--+(1 row)
--+
--+SELECT to_json(TRUE::TEXT)::TEXT = '"' || TRUE || '"';
--+ ?column?
--+----------
--+ t
--+(1 row)
--+
--+SELECT to_json(FALSE::TEXT)::TEXT = '"' || FALSE || '"';
--+ ?column?
--+----------
--+ t
--+(1 row)
--+
--+-- array
--+SELECT to_json(ARRAY[1,2,3]);
--+ERROR: to_json does not support conversion from arrays yet
--+-- Invalid types
--+SELECT to_json(row(1,2));
--+ERROR: to_json: cannot convert record to JSON
--+SELECT to_json('127.0.0.1'::INET);
--+ERROR: to_json: cannot convert inet to JSON
--diff --git a/contrib/json/json.sql.in b/contrib/json/json.sql.in
--index bbb0379..a2426e8 100644
----- a/contrib/json/json.sql.in
--+++ b/contrib/json/json.sql.in
--@@ -44,3 +44,7 @@ RETURNS json_type_t
-- AS 'MODULE_PATHNAME','json_get_type'
-- LANGUAGE C STRICT IMMUTABLE;
--
--+CREATE OR REPLACE FUNCTION to_json(anyelement)
--+RETURNS json
--+AS 'MODULE_PATHNAME'
--+LANGUAGE C IMMUTABLE; -- not STRICT; allows to_json(NULL) to return 'null'::json.
--diff --git a/contrib/json/json_ops.c b/contrib/json/json_ops.c
--deleted file mode 100644
--index db2502f..0000000
----- a/contrib/json/json_ops.c
--+++ /dev/null
--@@ -1,54 +0,0 @@
---#include "json.h"
---
---#define PG_RETURN_ENUM(typname, label) return enumLabelToOid(typname, label)
---
---static Oid enumLabelToOid(const char *typname, const char *label)
---{
--- Oid enumtypoid;
--- HeapTuple tup;
--- Oid ret;
---
--- enumtypoid = TypenameGetTypid(typname);
--- Assert(OidIsValid(enumtypoid));
---
--- tup = SearchSysCache2(ENUMTYPOIDNAME,
--- ObjectIdGetDatum(enumtypoid),
--- CStringGetDatum(label));
--- Assert(HeapTupleIsValid(tup));
---
--- ret = HeapTupleGetOid(tup);
---
--- ReleaseSysCache(tup);
---
--- return ret;
---}
---
---static const char *enum_type_names[JSON_TYPE_COUNT] = {
--- "null",
--- "string",
--- "number",
--- "bool",
--- "object",
--- "array"
---};
---
---/* json_type(json). Renamed to avoid clashing
--- * with the typedef enum of the same name. */
---PG_FUNCTION_INFO_V1(json_get_type);
---Datum json_get_type(PG_FUNCTION_ARGS);
---Datum
---json_get_type(PG_FUNCTION_ARGS)
---{
--- jsontype *t = PG_GETARG_JSON_P(0);
--- json_type type;
---
--- type = json_text_type(VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t));
---
--- if (!json_type_is_valid(type)) {
--- /* This should never happen */
--- elog(ERROR, "Corrupt JSON content");
--- type = JSON_NULL;
--- }
---
--- PG_RETURN_ENUM("json_type_t", enum_type_names[type]);
---}
--diff --git a/contrib/json/sql/json.sql b/contrib/json/sql/json.sql
--index 4506c9a..472af1e 100644
----- a/contrib/json/sql/json.sql
--+++ b/contrib/json/sql/json.sql
--@@ -49,3 +49,68 @@ INSERT INTO testjson VALUES ('{}');
-- SELECT * FROM testjson;
--
-- SELECT json_type(j) FROM testjson;
--+
--+-- null
--+SELECT to_json(NULL);
--+SELECT to_json(NULL::INT);
--+SELECT to_json(NULL::VOID);
--+SELECT to_json(NULL::MONEY);
--+SELECT json_type(to_json(NULL));
--+SELECT json_type(to_json(NULL::INT));
--+SELECT json_type(to_json(NULL::VOID));
--+SELECT json_type(to_json(NULL::MONEY));
--+
--+-- string
--+SELECT to_json('');
--+SELECT json_type(to_json(''));
--+SELECT to_json('string');
--+SELECT json_type(to_json('string'));
--+SELECT to_json('string'::VARCHAR);
--+SELECT json_type(to_json('string'::VARCHAR));
--+SELECT to_json('string'::VARCHAR(3));
--+SELECT json_type(to_json('string'::VARCHAR(3)));
--+SELECT to_json('{1,2,3}'::TEXT);
--+SELECT json_type(to_json('{1,2,3}'::TEXT));
--+SELECT to_json('"doubly-encoded"'::JSON);
--+SELECT json_type(to_json('"doubly-encoded"'::JSON));
--+SELECT to_json('"nested quotes"'::TEXT);
--+SELECT json_type(to_json('"nested quotes"'::TEXT));
--+SELECT to_json('"nested quotes"'::TEXT)::TEXT::JSON;
--+SELECT json_type(to_json('"nested quotes"'::TEXT)::TEXT::JSON);
--+SELECT to_json('h'::CHAR);
--+SELECT json_type(to_json('h'::CHAR));
--+SELECT to_json('hello world'::CHAR);
--+SELECT json_type(to_json('hello world'::CHAR));
--+SELECT to_json('hello world!'::CHAR(11));
--+SELECT json_type(to_json('hello world!'::CHAR(11)));
--+
--+
--+-- number
--+SELECT to_json(12345);
--+SELECT to_json(12345.678);
--+SELECT json_type(to_json(12345));
--+SELECT json_type(to_json(12345.678));
--+SELECT to_json(+1.23e100::FLOAT);
--+SELECT to_json('+1.23e100'::FLOAT);
--+SELECT to_json(123456789012345678901234567890123456789012345678901234567890.123456789012345678901234567890123456789012345678901234567890);
--+SELECT json_type(to_json(123456789012345678901234567890123456789012345678901234567890.123456789012345678901234567890123456789012345678901234567890));
--+SELECT to_json('100'::MONEY);
--+
--+-- bool
--+SELECT to_json(TRUE);
--+SELECT to_json(FALSE);
--+SELECT to_json(1=1);
--+SELECT to_json(1=2);
--+SELECT json_type(to_json(TRUE));
--+SELECT json_type(to_json(FALSE));
--+SELECT json_type(to_json(1=1));
--+SELECT json_type(to_json(1=2));
--+SELECT to_json(TRUE::TEXT)::TEXT = '"' || TRUE || '"';
--+SELECT to_json(FALSE::TEXT)::TEXT = '"' || FALSE || '"';
--+
--+-- array
--+SELECT to_json(ARRAY[1,2,3]);
--+
--+-- Invalid types
--+SELECT to_json(row(1,2));
--+SELECT to_json('127.0.0.1'::INET);
diff --git a/contrib/json/polymorphism-difficulty-blurb b/contrib/json/polymorphism-difficulty-blurb
deleted file mode 100644
index 64571b3..0000000
--- a/contrib/json/polymorphism-difficulty-blurb
+++ /dev/null
@@ -1,16 +0,0 @@
-One difficulty here will be deciding between whether to use polymorphism and/or overloading for to_json(). That is, whether or not to say:
-
--- polymorphism
-to_json(ANYELEMENT) RETURNS json
-
-or something like:
-
--- overloading
-to_json(TEXT) RETURNS json
-to_json(INT) RETURNS json
-to_json(FLOAT) RETURNS json
-to_json(BOOL) RETURNS json
-
-An issue I encountered with the polymorphic to_json is that saying to_json('string') by itself wouldn't work because the parser can't determine the type of 'string' in this context; the user would have to say to_json('string'::TEXT). However, requiring this cast may be better for clarity and flexibility. For instance:
-
-to_json('{1,2,3}'::INT[])
diff --git a/contrib/json/sql/json.sql b/contrib/json/sql/json.sql
index 472af1e..6e8aa86 100644
--- a/contrib/json/sql/json.sql
+++ b/contrib/json/sql/json.sql
@@ -50,7 +50,8 @@ SELECT * FROM testjson;
SELECT json_type(j) FROM testjson;
--- null
+
+-- to_json: null
SELECT to_json(NULL);
SELECT to_json(NULL::INT);
SELECT to_json(NULL::VOID);
@@ -60,7 +61,7 @@ SELECT json_type(to_json(NULL::INT));
SELECT json_type(to_json(NULL::VOID));
SELECT json_type(to_json(NULL::MONEY));
--- string
+-- to_json: string
SELECT to_json('');
SELECT json_type(to_json(''));
SELECT to_json('string');
@@ -84,8 +85,7 @@ SELECT json_type(to_json('hello world'::CHAR));
SELECT to_json('hello world!'::CHAR(11));
SELECT json_type(to_json('hello world!'::CHAR(11)));
-
--- number
+-- to_json: number
SELECT to_json(12345);
SELECT to_json(12345.678);
SELECT json_type(to_json(12345));
@@ -96,7 +96,7 @@ SELECT to_json(123456789012345678901234567890123456789012345678901234567890.1234
SELECT json_type(to_json(123456789012345678901234567890123456789012345678901234567890.123456789012345678901234567890123456789012345678901234567890));
SELECT to_json('100'::MONEY);
--- bool
+-- to_json: bool
SELECT to_json(TRUE);
SELECT to_json(FALSE);
SELECT to_json(1=1);
@@ -108,9 +108,53 @@ SELECT json_type(to_json(1=2));
SELECT to_json(TRUE::TEXT)::TEXT = '"' || TRUE || '"';
SELECT to_json(FALSE::TEXT)::TEXT = '"' || FALSE || '"';
--- array
+-- to_json: array
SELECT to_json(ARRAY[1,2,3]);
--- Invalid types
+-- to_json: invalid types
SELECT to_json(row(1,2));
SELECT to_json('127.0.0.1'::INET);
+
+
+-- from_json: null
+SELECT from_json(null);
+SELECT from_json(NULL::TEXT);
+SELECT from_json(NULL::JSON);
+
+-- from_json: string
+SELECT from_json('"valid string"');
+SELECT from_json($$ "hello\nworld" $$);
+
+-- from_json: number
+SELECT from_json('123');
+SELECT from_json('123')::INT;
+SELECT from_json('123.456')::INT;
+SELECT from_json('123.456')::FLOAT;
+SELECT from_json('123e-38');
+SELECT from_json('123e-38')::FLOAT;
+SELECT from_json('1.23e-38')::FLOAT;
+SELECT from_json('1.23e-38');
+SELECT from_json('1.23e-38')::NUMERIC;
+
+-- from_json: bool
+SELECT from_json('true')::JSON;
+SELECT from_json('true');
+SELECT from_json('true')::BOOLEAN;
+SELECT from_json('true')::BOOLEAN::JSON;
+SELECT from_json('true')::BOOLEAN::TEXT::JSON;
+SELECT from_json('false')::BOOLEAN::TEXT::JSON;
+SELECT from_json('false');
+SELECT from_json('f');
+SELECT from_json('t');
+SELECT from_json('f'::BOOLEAN::TEXT);
+SELECT from_json('f'::BOOLEAN::TEXT::JSON);
+SELECT from_json('t'::BOOLEAN::TEXT::JSON);
+
+-- from_json: object
+SELECT from_json('{"key": "value"}');
+
+-- from_json: array
+SELECT from_json('[1,2,3]');
+
+-- from_json: invalid
+SELECT from_json('invalid');
diff --git a/contrib/json/trash b/contrib/json/trash
deleted file mode 100644
index 7d922a6..0000000
--- a/contrib/json/trash
+++ /dev/null
@@ -1,144 +0,0 @@
-/* */
-
-typedef struct {
- Oid oid[JSON_TYPE_COUNT];
-} json_type_oids;
-
-/* enum-returning functions can't simply return the enum value;
- * they have to return an Oid representing the row on table pg_enum
- * representing the enum and desired value.
- *
- * This function memoizes those Oids. */
-static Oid get_json_type_oid(FmgrInfo *flinfo, json_type type)
-{
- json_type_oids *tbl = (json_type_oids*) flinfo->fn_extra;
-
- if (tbl == NULL) {
- int i;
-
- flinfo->fn_extra =
- MemoryContextAlloc(flinfo->fn_mcxt, sizeof(*tbl));
- tbl = (json_type_oids*)flinfo->fn_extra;
-
- for (i = 0; i < JSON_TYPE_COUNT; i++)
- tbl->oid[i] = InvalidOid;
- }
-
- Assert(JSON_TYPE_COUNT == sizeof(enum_type_names) / sizeof(*enum_type_names));
- Assert(type >= 0 && type < JSON_TYPE_COUNT);
-
- if (tbl->oid[type] == InvalidOid)
- tbl->oid[type] = enumLabelToOid("json_type_t", enum_type_names[type]);
- else
- elog(DEBUG1, "Memoization invoked for JSON type '%s'", enum_type_names[type]);
-
- return tbl->oid[type];
-}
-
-/*
-static Form_pg_type getTypeStruct(const char *typname)
-{
- Oid typid;
- HeapTuple typeTuple;
- Form_pg_type typeStruct;
-
- typid = TypenameGetTypid(typname);
- if (typid == InvalidOid) {
- elog(ERROR, "Type \"%s\" not found");
- return NULL;
- }
-
- typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
- if (!HeapTupleIsValid(typeTuple)) {
- elog(ERROR, "cache lookup failed for type %u", typid);
- return NULL;
- }
-
- typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
-
- return typeStruct;
-}
-*/
-
-#if 0
-typedef struct
-{
- char *label;
- Oid oid;
-} EnumTableEntry;
-
-typedef struct
-{
- int count;
- EnumTableEntry ent[1]; /* variable length array */
-} EnumTable;
-
-static void getEnumTable(const char *typname)
-{
- Oid typid;
- CatCList *list;
- int i;
- int nmemb;
- EnumTableEntry *tbl;
- Size tbl_alloc;
-
- typid = TypenameGetTypid(typname);
- if (typid == InvalidOid) {
- elog(ERROR, "Type \"%s\" not found", typname);
- return NULL;
- }
-
- list = SearchSysCacheList1(ENUMTYPOIDNAME, ObjectIdGetDatum(typid));
- nmemb = list->n_members;
-
- tbl_alloc = sizeof(EnumTable)
- - sizeof(EnumTableEntry)
- + nmemb * sizeof(EnumTableEntry);
- tbl = palloc(tbl_alloc);
-
- for (i = 0; i < nmemb; i++) {
- HeapTuple tuple = &list->members[i]->tuple;
- Oid oid = HeapTupleHeaderGetOid(tuple.t_data);
- Form_pg_enum en = (Form_pg_enum) GETSTRUCT(tuple);
- char *label = pstrdup(NameStr(en->enumlabel));
- }
-
- ReleaseSysCacheList(list);
-}
-
-#endif
-
-#if 0
-static Oid enumLabelToOid(const char *typname, const char *label)
-{
- Oid typid;
- HeapTuple typeTuple;
- Form_pg_type typeStruct;
- regproc typinput;
- Datum d;
- Oid ret;
-
- typid = TypenameGetTypid(typname);
- if (typid == InvalidOid) {
- elog(ERROR, "Type \"%s\" not found", typname);
- return InvalidOid;
- }
-
- typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
- if (!HeapTupleIsValid(typeTuple)) {
- elog(ERROR, "cache lookup failed for type %u", typid);
- return InvalidOid;
- }
-
- typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
- typinput = typeStruct->typinput;
-
- ReleaseSysCache(typeTuple);
-
- d = OidInputFunctionCall(typinput, (char*)label, typid, -1);
-
- ret = DatumGetObjectId(d);
-
- return ret;
-}
-#endif