From 15e75faf8cf4d78f0e9c2c957e453e5e76b87571 Mon Sep 17 00:00:00 2001
From: Julien Lopez <julien.lopez@lri.fr>
Date: Thu, 26 Jan 2017 12:45:09 +0100
Subject: [PATCH] Add methods and class for PL/JAVA and a test with side
 effects

---
 .../com/oracle/truffle/r/engine/REngine.java  | 26 ++++++++
 .../com/oracle/truffle/r/runtime/RValue.java  | 59 +++++++++++++++++++
 .../tests/pgsql/QuerySideEffect.R             | 16 +++++
 3 files changed, 101 insertions(+)
 create mode 100644 com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RValue.java
 create mode 100644 com.oracle.truffle.r.test/tests/pgsql/QuerySideEffect.R

diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
index be70203b89..86f938fe3b 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
@@ -23,6 +23,8 @@
 package com.oracle.truffle.r.engine;
 
 import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
 import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -78,6 +80,7 @@ import com.oracle.truffle.r.runtime.RProfile;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RSource;
 import com.oracle.truffle.r.runtime.RStartParams.SA_TYPE;
+import com.oracle.truffle.r.runtime.RValue;
 import com.oracle.truffle.r.runtime.ReturnException;
 import com.oracle.truffle.r.runtime.RootWithBody;
 import com.oracle.truffle.r.runtime.SubstituteVirtualFrame;
@@ -308,6 +311,29 @@ final class REngine implements Engine, Engine.Timings {
         }
     }
 
+    public static final RValue executeR(final String program) throws IOException {
+        return new RValue(
+                        (Serializable) RContext.getEngine().parseAndEval(Source.newBuilder(program).name("RBuilder").mimeType(RRuntime.R_APP_MIME).build(), REnvironment.baseEnv().getFrame(), false));
+    }
+
+    public static final RValue executeApply(final RValue fun, final RValue args[]) throws IOException {
+        final String program = "f = " + fun + "\nf(" + Arrays.stream(args).map(arg -> arg.getValue().toString()).collect(Collectors.joining(", ")) + ")";
+        return new RValue(
+                        (Serializable) RContext.getEngine().parseAndEval(Source.newBuilder(program).name("RBuilder").mimeType(RRuntime.R_APP_MIME).build(), REnvironment.baseEnv().getFrame(), false));
+    }
+
+    public static final RValue translate(final Integer i) throws IOException {
+        return new RValue(i);
+    }
+
+    public static final RValue translate(final String s) throws IOException {
+        return new RValue(s);
+    }
+
+    public static final RValue translate(final Boolean b) throws IOException {
+        return new RValue(b);
+    }
+
     private final class PolyglotEngineRootNode extends RootNode {
 
         private final List<RSyntaxNode> statements;
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RValue.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RValue.java
new file mode 100644
index 0000000000..84f0ccb7fd
--- /dev/null
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RValue.java
@@ -0,0 +1,59 @@
+package com.oracle.truffle.r.runtime;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.sql.SQLData;
+import java.sql.SQLException;
+import java.sql.SQLInput;
+import java.sql.SQLOutput;
+import java.util.Base64;
+
+public class RValue implements SQLData {
+    private Serializable value = null;
+    private String base64 = null;
+    private String typeName = null;
+
+    public RValue() {
+    }
+
+    public RValue(Serializable value) throws IOException {
+        this.value = value;
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(baos);
+        oos.writeObject(value);
+        oos.close();
+        base64 = Base64.getEncoder().encodeToString(baos.toByteArray());
+    }
+
+    public final Serializable getValue() {
+        return this.value;
+    }
+
+    @Override
+    public final String getSQLTypeName() throws SQLException {
+        return this.typeName;
+    }
+
+    @Override
+    public final void readSQL(SQLInput stream, String type) throws SQLException {
+        base64 = stream.readString();
+        byte[] data = Base64.getDecoder().decode(base64);
+        try {
+            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
+            value = (Serializable) ois.readObject();
+            ois.close();
+            typeName = type;
+        } catch (IOException | ClassNotFoundException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    @Override
+    public final void writeSQL(SQLOutput stream) throws SQLException {
+        stream.writeString(base64);
+    }
+}
diff --git a/com.oracle.truffle.r.test/tests/pgsql/QuerySideEffect.R b/com.oracle.truffle.r.test/tests/pgsql/QuerySideEffect.R
new file mode 100644
index 0000000000..30789e289f
--- /dev/null
+++ b/com.oracle.truffle.r.test/tests/pgsql/QuerySideEffect.R
@@ -0,0 +1,16 @@
+emp = new.tableRef("emp", "PostgreSQL", "postgre.config", "public")
+minsalary = 2500
+q = select(function (x) {
+             res = new.env()
+             res$empno = x$empno
+             res$ename = x$ename
+             res$salary = function (dol){
+               a = dol * 89 / 100
+               while (a > 1000) a = a * 89 / 100
+               a
+             }(x$sal)
+             res },
+    where(function (x) x$sal >= minsalary,
+    from(emp)))
+results = query.force(q)
+print(results)
-- 
GitLab