diff options
| author | Joey Adams | 2010-06-09 03:23:34 +0000 |
|---|---|---|
| committer | Joey Adams | 2010-06-09 03:23:34 +0000 |
| commit | 27d164bc9af93c9fe87649367248b7b794d1aacd (patch) | |
| tree | 4d40829424afb05fce7a2e8d3ebaf374a814cf45 | |
| parent | 88262d4c8b922673e56e3dc9452dd29b85ace641 (diff) | |
Implemented from_json (for basic types, just like to_json) along with testcases.
| -rw-r--r-- | contrib/json/expected/json.out | 170 | ||||
| -rw-r--r-- | contrib/json/json.sql.in | 5 | ||||
| -rw-r--r-- | contrib/json/json_io.c | 48 | ||||
| -rw-r--r-- | contrib/json/out | 21 | ||||
| -rw-r--r-- | contrib/json/out.diff | 433 | ||||
| -rw-r--r-- | contrib/json/polymorphism-difficulty-blurb | 16 | ||||
| -rw-r--r-- | contrib/json/sql/json.sql | 58 | ||||
| -rw-r--r-- | contrib/json/trash | 144 |
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 |
