You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by wy...@apache.org on 2021/11/24 00:32:37 UTC

[asterixdb] branch master updated: [ASTERIXDB-2990][FUN] Introduce parse_json()

This is an automated email from the ASF dual-hosted git repository.

wyk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 79379d8  [ASTERIXDB-2990][FUN] Introduce parse_json()
79379d8 is described below

commit 79379d8ebbb74f2f784a63c4a85fcfb2f1f979c4
Author: Wail Alkowaileet <wa...@gmail.com>
AuthorDate: Mon Nov 22 21:54:11 2021 -0800

    [ASTERIXDB-2990][FUN] Introduce parse_json()
    
    - user model changes: yes
    - storage format changes: no
    - interface changes: no
    
    Details:
    Introduce parse_json() function to parse string values as ADM
    
    Change-Id: I1be6eb2a5abaffa4b4dffba93d5bf91d46f4fcb8
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/14123
    Reviewed-by: Wael Alkowaileet <wa...@gmail.com>
    Reviewed-by: Ali Alsuliman <al...@gmail.com>
    Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>
---
 .../parse-json-function.1.query.sqlpp              |  31 ++++++
 .../parse-json-function.2.query.sqlpp              |  21 ++++
 .../parse-json-function.3.query.sqlpp              |  22 ++++
 .../parse-json-function/parse-json-function.1.adm  |   1 +
 .../parse-json-function/parse-json-function.2.adm  |   7 ++
 .../parse-json-function/parse-json-function.3.adm  |   6 ++
 .../test/resources/runtimets/testsuite_sqlpp.xml   |   8 ++
 .../external/parser/AbstractJsonDataParser.java    |  11 +-
 .../RuntimeParserFunctionRegistrant.java           |  31 ++++++
 .../evaluators/StringJsonParseDescriptor.java      |  86 ++++++++++++++++
 .../parser/evaluators/StringJsonParseEval.java     | 113 +++++++++++++++++++++
 ...apache.asterix.om.functions.IFunctionRegistrant |  20 ++++
 .../asterix/om/functions/BuiltinFunctions.java     |   3 +
 13 files changed, 353 insertions(+), 7 deletions(-)

diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/json-parser/parse-json-function/parse-json-function.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/json-parser/parse-json-function/parse-json-function.1.query.sqlpp
new file mode 100644
index 0000000..194983d
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/json-parser/parse-json-function/parse-json-function.1.query.sqlpp
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+-- param max-warnings:json=1000
+
+SELECT
+    parse_json('null') nullVal,
+    parse_json('1') intVal,
+    parse_json('"stringVal"') stringVal,
+    parse_json('3.75') doubleVal,
+    parse_json('{"id": 7, "name": "Jerry", "comment": "\uD83D\uDE22\uD83D\uDE22\uD83D\uDC89\uD83D\uDC89 = 𩸽 😢😢💉💉. Coffee ☕‼️😃. حسنا"}') objectVal,
+    parse_json('[1,2,3]') arrayVal,
+    parse_json(null) nullArgVal,
+    parse_json(missing) missingArgVal,
+    parse_json(1) unexpectedType,
+    parse_json('') emptyString
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/json-parser/parse-json-function/parse-json-function.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/json-parser/parse-json-function/parse-json-function.2.query.sqlpp
new file mode 100644
index 0000000..81c7944
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/json-parser/parse-json-function/parse-json-function.2.query.sqlpp
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+SELECT parse_json(v) multipleValues
+FROM ['', '{"a":1}', '[1, 2]', '{"c": "test"}', '{"a":3.57}', '["a", "b"]', '{"c":{"d":1}}'] v
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/json-parser/parse-json-function/parse-json-function.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/json-parser/parse-json-function/parse-json-function.3.query.sqlpp
new file mode 100644
index 0000000..cd4fc4c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/json-parser/parse-json-function/parse-json-function.3.query.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+-- param max-warnings:json=1000
+
+SELECT parse_json(v) malformedVal
+FROM ['{"a":}', '[1, 2]', '{"c": "test"}', '{"a":}', '["a", "b"]', '{"c":{"d":1}}'] v
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/json-parser/parse-json-function/parse-json-function.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/json-parser/parse-json-function/parse-json-function.1.adm
new file mode 100644
index 0000000..a59c66d
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/json-parser/parse-json-function/parse-json-function.1.adm
@@ -0,0 +1 @@
+{ "nullVal": null, "intVal": 1, "stringVal": "stringVal", "doubleVal": 3.75, "objectVal": { "id": 7, "name": "Jerry", "comment": "😢😢💉💉 = 𩸽 😢😢💉💉. Coffee ☕‼️😃. حسنا" }, "arrayVal": [ 1, 2, 3 ], "nullArgVal": null, "unexpectedType": null, "emptyString": null }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/json-parser/parse-json-function/parse-json-function.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/json-parser/parse-json-function/parse-json-function.2.adm
new file mode 100644
index 0000000..533d942
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/json-parser/parse-json-function/parse-json-function.2.adm
@@ -0,0 +1,7 @@
+{ "multipleValues": null }
+{ "multipleValues": { "a": 1 } }
+{ "multipleValues": [ 1, 2 ] }
+{ "multipleValues": { "c": "test" } }
+{ "multipleValues": { "a": 3.57 } }
+{ "multipleValues": [ "a", "b" ] }
+{ "multipleValues": { "c": { "d": 1 } } }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/json-parser/parse-json-function/parse-json-function.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/json-parser/parse-json-function/parse-json-function.3.adm
new file mode 100644
index 0000000..41bc026
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/json-parser/parse-json-function/parse-json-function.3.adm
@@ -0,0 +1,6 @@
+{ "malformedVal": null }
+{ "malformedVal": [ 1, 2 ] }
+{ "malformedVal": { "c": "test" } }
+{ "malformedVal": null }
+{ "malformedVal": [ "a", "b" ] }
+{ "malformedVal": { "c": { "d": 1 } } }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index cbde37e..7ea397e 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -15113,6 +15113,14 @@
         <source-location>false</source-location>
       </compilation-unit>
     </test-case>
+    <test-case FilePath="json-parser" check-warnings="true">
+      <compilation-unit name="parse-json-function">
+        <output-dir compare="Text">parse-json-function</output-dir>
+        <source-location>false</source-location>
+        <expected-warn>Type mismatch: function parse-json expects its 1st input parameter to be of type string, but the actual input type is bigint</expected-warn>
+        <expected-warn>Malformed input stream</expected-warn>
+      </compilation-unit>
+    </test-case>
   </test-group>
   <test-group name="composite-key">
     <test-case FilePath="composite-key">
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/AbstractJsonDataParser.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/AbstractJsonDataParser.java
index b59dd1c..9a602de 100644
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/AbstractJsonDataParser.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/AbstractJsonDataParser.java
@@ -73,10 +73,8 @@ public abstract class AbstractJsonDataParser extends AbstractNestedDataParser<AD
     /**
      * Initialize JSONDataParser with GeometryCoParser
      *
-     * @param recordType
-     *            defined type.
-     * @param jsonFactory
-     *            Jackson JSON parser factory.
+     * @param recordType  defined type.
+     * @param jsonFactory Jackson JSON parser factory.
      */
     public AbstractJsonDataParser(ARecordType recordType, JsonFactory jsonFactory) {
         // recordType currently cannot be null, however this is to guarantee for any future changes.
@@ -101,7 +99,7 @@ public abstract class AbstractJsonDataParser extends AbstractNestedDataParser<AD
             parseValue(BuiltinType.ANY, out);
             return true;
         } catch (IOException e) {
-            throw new RuntimeDataException(ErrorCode.RECORD_READER_MALFORMED_INPUT_STREAM, e);
+            throw createException(e);
         }
     }
 
@@ -238,8 +236,7 @@ public abstract class AbstractJsonDataParser extends AbstractNestedDataParser<AD
     /**
      * Geometry in GeoJSON is an object
      *
-     * @param typeTag
-     *            geometry typeTag
+     * @param typeTag geometry typeTag
      * @param out
      * @throws IOException
      */
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/evaluators/RuntimeParserFunctionRegistrant.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/evaluators/RuntimeParserFunctionRegistrant.java
new file mode 100644
index 0000000..a3fd0ff
--- /dev/null
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/evaluators/RuntimeParserFunctionRegistrant.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.external.parser.evaluators;
+
+import org.apache.asterix.om.functions.IFunctionCollection;
+import org.apache.asterix.om.functions.IFunctionRegistrant;
+
+public class RuntimeParserFunctionRegistrant implements IFunctionRegistrant {
+    private static final long serialVersionUID = -2204964196487084743L;
+
+    @Override
+    public void register(IFunctionCollection collection) {
+        collection.add(StringJsonParseDescriptor.FACTORY);
+    }
+}
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/evaluators/StringJsonParseDescriptor.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/evaluators/StringJsonParseDescriptor.java
new file mode 100644
index 0000000..a548fec
--- /dev/null
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/evaluators/StringJsonParseDescriptor.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.external.parser.evaluators;
+
+import static org.apache.asterix.om.functions.BuiltinFunctions.STRING_PARSE_JSON;
+
+import java.io.IOException;
+
+import org.apache.asterix.common.annotations.MissingNullInOutFunction;
+import org.apache.asterix.external.parser.JSONDataParser;
+import org.apache.asterix.external.parser.factory.JSONDataParserFactory;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.context.IHyracksTaskContext;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.api.exceptions.SourceLocation;
+
+/**
+ * the function parse-json() accepts a string and produces an ADM value
+ * Example:
+ * SELECT VALUE parse_json('[1,2]')
+ * <p>
+ * Output:
+ * [1, 2]
+ */
+@MissingNullInOutFunction
+public class StringJsonParseDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+    private static final long serialVersionUID = 1119187597484196172L;
+    public static final IFunctionDescriptorFactory FACTORY = StringJsonParseDescriptor::new;
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return STRING_PARSE_JSON;
+    }
+
+    @Override
+    public IScalarEvaluatorFactory createEvaluatorFactory(IScalarEvaluatorFactory[] args) throws AlgebricksException {
+        return new StringJsonParseEvalFactory(args[0], sourceLoc);
+    }
+
+    public static class StringJsonParseEvalFactory implements IScalarEvaluatorFactory {
+        private static final long serialVersionUID = 7976257476594454552L;
+        private final IScalarEvaluatorFactory stringEvalFactory;
+        private final SourceLocation sourceLocation;
+
+        public StringJsonParseEvalFactory(IScalarEvaluatorFactory stringEvalFactory, SourceLocation sourceLocation) {
+            this.stringEvalFactory = stringEvalFactory;
+            this.sourceLocation = sourceLocation;
+        }
+
+        @Override
+        public IScalarEvaluator createScalarEvaluator(IEvaluatorContext ctx) throws HyracksDataException {
+            try {
+                return new StringJsonParseEval(ctx, stringEvalFactory.createScalarEvaluator(ctx),
+                        createParser(ctx.getTaskContext()), sourceLocation);
+            } catch (IOException e) {
+                throw HyracksDataException.create(e);
+            }
+        }
+
+        private JSONDataParser createParser(IHyracksTaskContext ctx) throws HyracksDataException {
+            return (JSONDataParser) new JSONDataParserFactory().createInputStreamParser(ctx, 0);
+        }
+    }
+}
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/evaluators/StringJsonParseEval.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/evaluators/StringJsonParseEval.java
new file mode 100644
index 0000000..5c15f15
--- /dev/null
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/parser/evaluators/StringJsonParseEval.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.external.parser.evaluators;
+
+import static org.apache.asterix.om.functions.BuiltinFunctions.STRING_PARSE_JSON;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.external.parser.JSONDataParser;
+import org.apache.asterix.om.exceptions.ExceptionUtil;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.runtime.evaluators.functions.PointableHelper;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.api.exceptions.IWarningCollector;
+import org.apache.hyracks.api.exceptions.SourceLocation;
+import org.apache.hyracks.api.exceptions.Warning;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.primitive.UTF8StringPointable;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.hyracks.data.std.util.ByteArrayAccessibleInputStream;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+public class StringJsonParseEval implements IScalarEvaluator {
+    private final IEvaluatorContext ctx;
+    private final IScalarEvaluator inputEval;
+    private final JSONDataParser parser;
+    private final SourceLocation sourceLocation;
+    private final IPointable inputVal;
+    private final UTF8StringPointable utf8Val;
+    private final ByteArrayAccessibleInputStream inputStream;
+    private final ArrayBackedValueStorage resultStorage;
+    private final DataOutput out;
+
+    public StringJsonParseEval(IEvaluatorContext ctx, IScalarEvaluator inputEval, JSONDataParser parser,
+            SourceLocation sourceLocation) throws IOException {
+        this.ctx = ctx;
+        this.inputEval = inputEval;
+        this.parser = parser;
+        this.sourceLocation = sourceLocation;
+        inputVal = new VoidPointable();
+        utf8Val = new UTF8StringPointable();
+        inputStream = new ByteArrayAccessibleInputStream(new byte[0], 0, 0);
+        resultStorage = new ArrayBackedValueStorage();
+        out = resultStorage.getDataOutput();
+        parser.setInputStream(inputStream);
+    }
+
+    @Override
+    public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
+        inputEval.evaluate(tuple, inputVal);
+
+        if (PointableHelper.checkAndSetMissingOrNull(result, inputVal)) {
+            return;
+        }
+
+        byte[] bytes = inputVal.getByteArray();
+        int offset = inputVal.getStartOffset();
+        if (bytes[offset] == ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
+            utf8Val.set(bytes, offset + 1, inputVal.getLength() - 1);
+            inputStream.setContent(bytes, utf8Val.getCharStartOffset(), utf8Val.getUTF8Length());
+            resultStorage.reset();
+            try {
+                if (parser.parseAnyValue(out)) {
+                    result.set(resultStorage);
+                    return;
+                } else {
+                    //Reset the parser: EOF was encountered
+                    resetParser();
+                }
+            } catch (HyracksDataException e) {
+                IWarningCollector warningCollector = ctx.getWarningCollector();
+                if (warningCollector.shouldWarn()) {
+                    warningCollector.warn(Warning.of(sourceLocation, ErrorCode.RECORD_READER_MALFORMED_INPUT_STREAM));
+                }
+                //Reset the parser: An error was encountered.
+                resetParser();
+            }
+        } else {
+            ExceptionUtil.warnTypeMismatch(ctx, sourceLocation, STRING_PARSE_JSON, bytes[offset], 0, ATypeTag.STRING);
+        }
+
+        PointableHelper.setNull(result);
+    }
+
+    private void resetParser() throws HyracksDataException {
+        try {
+            parser.reset(inputStream);
+        } catch (IOException e) {
+            throw HyracksDataException.create(e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/asterixdb/asterix-external-data/src/main/resources/META-INF/services/org.apache.asterix.om.functions.IFunctionRegistrant b/asterixdb/asterix-external-data/src/main/resources/META-INF/services/org.apache.asterix.om.functions.IFunctionRegistrant
new file mode 100644
index 0000000..c3423da
--- /dev/null
+++ b/asterixdb/asterix-external-data/src/main/resources/META-INF/services/org.apache.asterix.om.functions.IFunctionRegistrant
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+org.apache.asterix.external.parser.evaluators.RuntimeParserFunctionRegistrant
\ No newline at end of file
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
index d50a1e5..0a1a8e9 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
@@ -500,6 +500,8 @@ public class BuiltinFunctions {
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "repeat", 2);
     public static final FunctionIdentifier STRING_SPLIT =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "split", 2);
+    public static final FunctionIdentifier STRING_PARSE_JSON =
+            new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "parse-json", 1);
 
     public static final FunctionIdentifier DATASET =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "dataset", FunctionIdentifier.VARARGS); // 1 or 2
@@ -1923,6 +1925,7 @@ public class BuiltinFunctions {
         addFunction(STRING_JOIN, StringJoinTypeComputer.INSTANCE, true);
         addFunction(STRING_REPEAT, AStringTypeComputer.INSTANCE_NULLABLE, true);
         addFunction(STRING_SPLIT, UniformInputTypeComputer.STRING_STRING_LIST_INSTANCE, true);
+        addFunction(STRING_PARSE_JSON, AnyTypeComputer.INSTANCE, true);
 
         addPrivateFunction(ORDERED_LIST_CONSTRUCTOR, OrderedListConstructorTypeComputer.INSTANCE, true);
         addFunction(POINT_CONSTRUCTOR, APointTypeComputer.INSTANCE, true);