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 be70203b89111b5f4efcf6dd7c6b29172e53723c..86f938fe3be54e41b91c3c8edaaefac88e3b91d6 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 0000000000000000000000000000000000000000..84f0ccb7fdc653648264e7511b4ed8ade3899ffb --- /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 0000000000000000000000000000000000000000..30789e289fa3cd71db223e1f011744b62275631d --- /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)