Browse files

Support json type conversion.

Now the json type is built-in since 9.2, it is reasonable to convert
the text representation to/from object.  V8 doesn't expose JsonParser
interface to C++ client, so we ended up extracting JSON.parse/stringify
from the global context.  There shouldn't be any performance gain
over the user script calling the functions, but it is only for convenience.
This breaks the existing script that calls JSON.parse/stringify.
  • Loading branch information...
1 parent 90190dc commit 7d60663692503399fd6144316f45438915b98801 @umitanuki umitanuki committed Dec 1, 2012
Showing with 51 additions and 3 deletions.
  1. +8 −3 Makefile
  2. +1 −0 doc/plv8.md
  3. +42 −0 plv8_type.cc
View
11 Makefile
@@ -35,7 +35,7 @@ DATA += plcoffee.control plcoffee--$(PLV8_VERSION).sql \
plls.control plls--$(PLV8_VERSION).sql
endif
DATA_built = plv8.sql
-REGRESS = init-extension plv8 inline json startup_pre startup varparam
+REGRESS = init-extension plv8 inline json startup_pre startup varparam json_conv
ifndef DISABLE_DIALECT
REGRESS += dialect
endif
@@ -73,14 +73,19 @@ all: $(DATA)
subclean:
rm -f plv8_config.h $(DATA) $(JSCS)
+ifeq ($(shell test $(PG_VERSION_NUM) -lt 90200 && echo yes), yes)
+REGRESS := $(filter-out json_conv, $(REGRESS))
+endif
+
else # < 9.1
ifeq ($(shell test $(PG_VERSION_NUM) -ge 90000 && echo yes), yes)
-REGRESS := init $(filter-out init-extension dialect, $(REGRESS))
+REGRESS := init $(filter-out init-extension dialect json_conv, $(REGRESS))
else # < 9.0
-REGRESS := init $(filter-out init-extension inline startup varparam dialect, $(REGRESS))
+REGRESS := init $(filter-out init-extension inline startup \
+ varparam dialect json_conv, $(REGRESS))
endif
View
1 doc/plv8.md
@@ -154,6 +154,7 @@ automatically. If the desired database type is one of
- date
- timestamp
- timestamptz
+- json (>= 9.2)
and the JS value looks compatible, then the conversion succeeds. Otherwise,
PL/v8 tries to convert them via cstring representation. An array type is
View
42 plv8_type.cc
@@ -179,6 +179,26 @@ ToScalarDatum(Handle<v8::Value> value, bool *isnull, plv8_type *type)
if (value->IsDate())
return EpochToTimestampTz(value->NumberValue());
break;
+#if PG_VERSION_NUM >= 90200
+ case JSONOID:
+ if (value->IsObject() || value->IsArray())
+ {
+ HandleScope scope;
+
+ Handle<Context> context = Context::GetCurrent();
+ Handle<Object> global = context->Global();
+
+ Handle<Object> JSON = global->Get(String::NewSymbol("JSON"))->ToObject();
+ Handle<Function> JSON_stringify =
+ Handle<Function>::Cast(JSON->Get(String::NewSymbol("stringify")));
+
+ Handle<v8::Value> result = JSON_stringify->Call(JSON, 1, &value);
+ CString str(result);
+
+ return CStringGetTextDatum(str);
+ }
+ break;
+#endif
}
/* Use lexical cast for non-numeric types. */
@@ -328,6 +348,28 @@ ToScalarValue(Datum datum, bool isnull, plv8_type *type)
pfree(p); // free if detoasted
return result;
}
+#if PG_VERSION_NUM >= 90200
+ case JSONOID:
+ {
+ void *p = PG_DETOAST_DATUM_PACKED(datum);
+ const char *str = VARDATA_ANY(p);
+ int len = VARSIZE_ANY_EXHDR(p);
+
+ Local<v8::Value> jsonString = ToString(str, len);
+
+ HandleScope scope;
+
+ Handle<Context> context = Context::GetCurrent();
+ Handle<Object> global = context->Global();
+
+ Handle<Object> JSON = global->Get(String::NewSymbol("JSON"))->ToObject();
+ Handle<Function> JSON_parse =
+ Handle<Function>::Cast(JSON->Get(String::NewSymbol("parse")));
+
+ // return JSON.parse.apply(JSON, jsonString);
+ return scope.Close(JSON_parse->Call(JSON, 1, &jsonString));
+ }
+#endif
default:
return ToString(datum, type);
}

0 comments on commit 7d60663

Please sign in to comment.