diff --git a/com.oracle.truffle.r.engine/hbase-site.xml b/com.oracle.truffle.r.engine/hbase-site.xml new file mode 100644 index 0000000000000000000000000000000000000000..31dd14dcb2e1e47a491832a98d9ae943d1ca9f2a --- /dev/null +++ b/com.oracle.truffle.r.engine/hbase-site.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<?xml-stylesheet type="text/xsl" href="configuration.xsl"?> +<!-- +/** + * + * 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. + */ +--> +<configuration> + <property> + <name>hbase.rootdir</name> + <value>file:///home/julien/hbase/root</value> + </property> + <property> + <name>hbase.zookeeper.property.dataDir</name> + <value>/home/julien/hbase/root/zookeeper</value> + </property> +</configuration> diff --git a/com.oracle.truffle.r.engine/oracle.config b/com.oracle.truffle.r.engine/oracle.config new file mode 100644 index 0000000000000000000000000000000000000000..676cc848c308c0a9303477005ca673d05b3017a8 --- /dev/null +++ b/com.oracle.truffle.r.engine/oracle.config @@ -0,0 +1,5 @@ +host = myoracle.com +sid = myview +port = 7658 +user = julilope +passwd = Pa$$w0rd diff --git a/com.oracle.truffle.r.engine/postgre.config b/com.oracle.truffle.r.engine/postgre.config new file mode 100644 index 0000000000000000000000000000000000000000..39dd278151eb10c99d66e7b091e5d6c342b355b4 --- /dev/null +++ b/com.oracle.truffle.r.engine/postgre.config @@ -0,0 +1,5 @@ +host = localhost +sid = postgres +port = 5432 +user = julien +passwd = Pa$$w0rd diff --git a/com.oracle.truffle.r.engine/postgre2.config b/com.oracle.truffle.r.engine/postgre2.config new file mode 100644 index 0000000000000000000000000000000000000000..8ef8ed55fbf64fc1ac673aa5f1ce3e526d6fb55f --- /dev/null +++ b/com.oracle.truffle.r.engine/postgre2.config @@ -0,0 +1,5 @@ +host = localhost +sid = other +port = 5432 +user = julien +passwd = Pa$$w0rd diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RExecute.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RExecute.java new file mode 100644 index 0000000000000000000000000000000000000000..2b0b2a3201f0ee596019ddc9a1ce691f37b3551b --- /dev/null +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RExecute.java @@ -0,0 +1,20 @@ +package com.oracle.truffle.r.engine; + +import java.io.Serializable; + +import org.apache.hadoop.hive.ql.exec.UDF; + +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.api.vm.PolyglotEngine.Value; +import com.oracle.truffle.r.runtime.RRuntime; + +public class RExecute extends UDF { + public static String evaluate(final String program) { + final Value v = PolyglotEngine.newBuilder().config("application/x-r", "REngine", null).build().eval(Source.newBuilder(program).name("RBuilder").mimeType(RRuntime.R_APP_MIME).build()); + final Object res = v.get(); + if (res instanceof Serializable) + return res.toString(); + return v.getSourceLocation().getCode(); + } +} diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RExecuteApply.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RExecuteApply.java new file mode 100644 index 0000000000000000000000000000000000000000..a9ed0dbe03ee7feb69a4c5443d9cea11295be5e3 --- /dev/null +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RExecuteApply.java @@ -0,0 +1,12 @@ +package com.oracle.truffle.r.engine; + +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.hadoop.hive.ql.exec.UDF; + +public class RExecuteApply extends UDF { + public static String evaluate(final String fun, final List<String> args) { + return RExecute.evaluate("f = " + fun + ";f(" + args.stream().map(arg -> arg.toString()).collect(Collectors.joining(", ")) + ")"); + } +} diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java index 65adfcfd0f9f825430961e248f74cbcbca055a18..382f3e47880672abb96d540d0f5cfd24fdba1d5b 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java @@ -22,8 +22,14 @@ */ package com.oracle.truffle.r.engine; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Serializable; +import java.io.StringWriter; +import java.util.Arrays; import java.util.HashMap; - +import java.util.Map; +import java.util.stream.Collectors; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.TruffleLanguage; @@ -33,17 +39,22 @@ import com.oracle.truffle.api.instrumentation.ProvidedTags; import com.oracle.truffle.api.instrumentation.StandardTags; import com.oracle.truffle.api.metadata.ScopeProvider; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.api.vm.PolyglotEngine.Value; import com.oracle.truffle.r.engine.interop.RForeignAccessFactoryImpl; import com.oracle.truffle.r.nodes.RASTBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinPackages; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.instrumentation.RSyntaxTags; +import com.oracle.truffle.r.nodes.qirinterface.QIRInterface; import com.oracle.truffle.r.runtime.ExitException; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RAccuracyInfo; import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RValue; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.context.Engine.IncompleteSourceException; import com.oracle.truffle.r.runtime.context.Engine.ParseException; @@ -123,6 +134,7 @@ public final class TruffleRLanguageImpl extends TruffleRLanguage implements Scop @Override protected void disposeContext(RContext context) { + QIRInterface.closeDrivers(); context.destroy(); } @@ -228,4 +240,72 @@ public final class TruffleRLanguageImpl extends TruffleRLanguage implements Scop public AbstractScope findScope(RContext langContext, Node node, Frame frame) { return RScope.createScope(node, frame); } + + public static final Map<String, RValue> valueCache = new HashMap<>(); + public static PolyglotEngine vm = null; + + public static final RValue executeR(final String program) { + if (vm == null) + vm = PolyglotEngine.newBuilder().config("application/x-r", "REngine", null).build(); + RValue res = valueCache.get(program); + if (res != null) + return res; + try { + final Value v = vm.eval(Source.newBuilder(program).name("RBuilder").mimeType(RRuntime.R_APP_MIME).build()); + final Object o = v.get(); + if (o instanceof Serializable) + res = new RValue((Serializable) o); + else + res = new RValue(v.getSourceLocation().getCode()); + valueCache.put(program, res); + return res; + } catch (Exception e) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + throw new RuntimeException(sw.toString()); + } + } + + public static final RValue executeApply(final RValue fun, final RValue args[]) { + return executeR("f = " + fun.getValue() + "\nf(" + Arrays.stream(args).map(arg -> arg.getValue().toString()).collect(Collectors.joining(", ")) + ")"); + } + + public static final String executeApply(final String fun, final String args[]) { + return executeR("f = " + fun + "\nf(" + + Arrays.stream(args).map(s -> s.equals("TRUE") ? s : s.equals("FALSE") ? s : s.matches("[A-Za-z_].*") ? "\"" + s + "\"" : s).collect(Collectors.joining(", ")) + + ")").getValue().toString(); + } + + public static final RValue translate(final Integer i) throws IOException { + return new RValue(i); + } + + public static final RValue translate(final Double d) throws IOException { + return new RValue(d); + } + + 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); + } + + public static final Integer translateBackToInteger(final RValue v) { + return (Integer) v.getValue(); + } + + public static final Double translateBackToDouble(final RValue v) { + return (Double) v.getValue(); + } + + public static final String translateBackToString(final RValue v) { + return (String) v.getValue(); + } + + public static final Boolean translateBackToBoolean(final RValue v) { + return (Boolean) v.getValue(); + } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index e1c3ca08e3b0899498abbe29882a93dc486d7462..22761219ac9546f0177dac0fba74038d96a6fbb7 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -117,6 +117,9 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRStackTraceNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRStats.FastRProfAttr; import com.oracle.truffle.r.nodes.builtin.fastr.FastRStats.FastRProfFuncounts; import com.oracle.truffle.r.nodes.builtin.fastr.FastRStats.FastRProfTypecounts; +import com.oracle.truffle.r.nodes.builtin.query.RForceQueryBuiltin; +import com.oracle.truffle.r.nodes.builtin.query.RForceQueryBuiltinNodeGen; +import com.oracle.truffle.r.nodes.builtin.query.RTableBuiltin; import com.oracle.truffle.r.nodes.builtin.fastr.FastRStatsFactory; import com.oracle.truffle.r.nodes.builtin.fastr.FastRSyntaxTree; import com.oracle.truffle.r.nodes.builtin.fastr.FastRSyntaxTreeNodeGen; @@ -132,6 +135,7 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRTry; import com.oracle.truffle.r.nodes.builtin.fastr.FastRTryNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastrDqrls; import com.oracle.truffle.r.nodes.builtin.fastr.FastrDqrlsNodeGen; +import com.oracle.truffle.r.nodes.builtin.query.RTableBuiltinNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.memprof.FastRprofmem; import com.oracle.truffle.r.nodes.builtin.fastr.memprof.FastRprofmemNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.memprof.FastRprofmemShow; @@ -741,6 +745,10 @@ public class BasePackage extends RBuiltinPackage { add(Xtfrm.class, XtfrmNodeGen::create); add(IsSingle.class, IsSingleNodeGen::create); + // query + add(RForceQueryBuiltin.class, RForceQueryBuiltinNodeGen::create); + add(RTableBuiltin.class, RTableBuiltinNodeGen::create); + // infix functions add(Subscript.class, SubscriptNodeGen::create, Subscript::special); add(Subscript.DefaultBuiltin.class, SubscriptNodeGen::create, Subscript::special); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AccessField.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AccessField.java index 1663b1ff5ace4d4cab3bd9c25712f45d953c911d..c40c9d62e8fd21afbe53ed68cf82510f9f19a082 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AccessField.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/AccessField.java @@ -31,6 +31,8 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode; @@ -43,12 +45,21 @@ import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.builtins.RSpecialFactory; +import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.nodes.RNode; +import qir.ast.QIRLambda; +import qir.ast.QIRVariable; +import qir.ast.data.QIRTcons; +import qir.ast.data.QIRTdestr; +import qir.ast.data.QIRTnil; +import qir.ast.operator.QIRProject; + @NodeChild(value = "arguments", type = RNode[].class) abstract class AccessFieldSpecial extends SpecialsUtils.ListFieldSpecialBase { @@ -103,6 +114,14 @@ public abstract class AccessField extends RBuiltinNode.Arg2 { if (!invalidAtomicVector.profile(container instanceof RAbstractListVector) && container instanceof RAbstractVector) { error.enter(); throw error(RError.Message.DOLLAR_ATOMIC_VECTORS); + } else if (container instanceof REnvironment && ((REnvironment) container).get("queryId") != null) { + final Object queryId = ((REnvironment) container).get("queryId"); + if (queryId != null) { + final QIRVariable v = new QIRVariable(null, "t"); + RContext.queries.set((int) queryId, new QIRProject(getSourceSection(), + new QIRLambda(null, null, v, new QIRTcons(null, field, new QIRTdestr(null, v, field), QIRTnil.instance), new FrameDescriptor()), RContext.queries.get((int) queryId))); + return container; + } } return extract.applyAccessField(container, field); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/query/RForceQueryBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/query/RForceQueryBuiltin.java new file mode 100644 index 0000000000000000000000000000000000000000..c600196a79f340ef4997254f1607c62525c676c1 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/query/RForceQueryBuiltin.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.query; + +import qir.ast.QIRNode; + +import static com.oracle.truffle.r.runtime.RVisibility.OFF; +import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; +import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.qirinterface.QIRInterface; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.env.REnvironment; + +/** + * This builtin takes a query and returns a data frame that are the results of this query. + */ +@RBuiltin(name = "query.force", visibility = OFF, kind = PRIMITIVE, parameterNames = {"query"}, behavior = COMPLEX) +public abstract class RForceQueryBuiltin extends RBuiltinNode.Arg1 { + static { + Casts.noCasts(RForceQueryBuiltin.class); + } + + @TruffleBoundary + @Specialization + public static final RList force(final REnvironment rQuery) { + // Every query is identified by an integer included in the object returned by the query. + final Object tmp = rQuery.get("queryId"); + final int queryId = tmp != null ? (int) tmp : RContext.INVALID_QUERY_ID; + if (queryId == RContext.INVALID_QUERY_ID) + throw new RuntimeException("Not a query object."); + + // TODO: Handle results given in streaming. + QIRNode query = RContext.queries.get(queryId); + if (query == null) + throw new RuntimeException("Unrecognized or empty query: " + queryId); + + final RList cachedResults = RContext.results.get(queryId); + if (cachedResults != null) // The query has been run before. + return cachedResults; + query = QIRInterface.normalize(query, RContext.envs.get(queryId)); + RContext.queries.set(queryId, query); + + final Map<String, List<Object>> rawResults = QIRInterface.run(query); + // Create the data frame. TODO: Find a simpler way. + final String frameCode = rawResults.entrySet().stream().map( + entry -> entry.getKey() + "=c(" + + String.join(",", entry.getValue().stream().map(x -> x instanceof String ? "\"" + x + "\"" : x.toString()).collect(Collectors.toList())) + + ")").collect(Collectors.joining("\n")) + + "\ndata.frame(" + String.join(", ", rawResults.keySet()) + ")"; + final RList queryResults = (RList) RContext.getEngine().parseAndEval( + Source.newBuilder(frameCode).name("ShouldNotExistBuilder").mimeType(RRuntime.R_APP_MIME).build(), + REnvironment.baseEnv().getFrame(), false); + RContext.results.set(queryId, queryResults); + + return queryResults; + } +} \ No newline at end of file diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/query/RTableBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/query/RTableBuiltin.java new file mode 100644 index 0000000000000000000000000000000000000000..59266673342dfe42f1a2e7cc3836bfa7fb81a0a8 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/query/RTableBuiltin.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.query; + +import static com.oracle.truffle.r.runtime.RVisibility.OFF; +import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; +import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; + +import com.oracle.truffle.api.CompilerDirectives.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.env.REnvironment.PutException; + +@RBuiltin(name = "new.tableRef", visibility = OFF, kind = PRIMITIVE, parameterNames = {"tableName", "dbName", "configFile", "schemaName"}, behavior = PURE) +public abstract class RTableBuiltin extends RBuiltinNode.Arg4 { + static { + Casts.noCasts(RTableBuiltin.class); + } + + @TruffleBoundary + @Specialization + public static final REnvironment table(final String tableName, final String dbName, final String configFile, final String schemaName) { + final REnvironment res = RDataFactory.createNewEnv(null); + + try { + res.put("tableName", tableName); + res.put("dbName", dbName); + res.put("configFile", configFile); + res.put("schemaName", schemaName); + } catch (PutException e) { + e.printStackTrace(); + } + return res; + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java index 9804249bf44414d431978d3717805b1b4cf7b260..c9b15ec27b5268dd74c9d2c14a40db624595a001 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java @@ -50,6 +50,15 @@ import com.oracle.truffle.r.nodes.function.RCallSpecialNode; import com.oracle.truffle.r.nodes.function.SaveArgumentsNode; import com.oracle.truffle.r.nodes.function.WrapDefaultArgumentNode; import com.oracle.truffle.r.nodes.function.signature.MissingNode; +import com.oracle.truffle.r.nodes.query.RFromNode; +import com.oracle.truffle.r.nodes.query.RGroupNode; +import com.oracle.truffle.r.nodes.query.RJoinNode; +import com.oracle.truffle.r.nodes.query.RLeftJoinNode; +import com.oracle.truffle.r.nodes.query.ROrderNode; +import com.oracle.truffle.r.nodes.query.RQueryVisitor; +import com.oracle.truffle.r.nodes.query.RRightJoinNode; +import com.oracle.truffle.r.nodes.query.RSelectNode; +import com.oracle.truffle.r.nodes.query.RWhereNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RRuntime; @@ -149,6 +158,51 @@ public final class RASTBuilder implements RCodeBuilder<RSyntaxNode> { return RCallSpecialNode.createCall(source, lhs.asRNode(), createSignature(args), createArguments(args)); } + @Override + public final RSyntaxNode handleQueries(final RSyntaxNode expression) { + return expression.accept(RQueryVisitor.instance); + } + + @Override + public final RSyntaxNode select(final SourceSection source, final RSyntaxNode formatter, final RSyntaxNode child) { + return new RSelectNode(source, formatter.asRNode(), child.asRNode()); + } + + @Override + public final RSyntaxNode from(final SourceSection source, final RSyntaxNode child) { + return new RFromNode(source, child.asRNode()); + } + + @Override + public final RSyntaxNode where(final SourceSection source, final RSyntaxNode filter, final RSyntaxNode child) { + return new RWhereNode(source, filter.asRNode(), child.asRNode()); + } + + @Override + public final RSyntaxNode groupby(final SourceSection source, final RSyntaxNode group, final RSyntaxNode child) { + return new RGroupNode(source, group.asRNode(), child.asRNode()); + } + + @Override + public final RSyntaxNode orderby(final SourceSection source, final RSyntaxNode order, final RSyntaxNode asc, final RSyntaxNode child) { + return new ROrderNode(source, order.asRNode(), asc.asRNode(), child.asRNode()); + } + + @Override + public final RSyntaxNode join(final SourceSection source, final RSyntaxNode child1, final RSyntaxNode child2, final RSyntaxNode f) { + return new RJoinNode(source, f.asRNode(), child1.asRNode(), child2.asRNode()); + } + + @Override + public final RSyntaxNode leftJoin(final SourceSection source, final RSyntaxNode child1, final RSyntaxNode child2, final RSyntaxNode f) { + return new RLeftJoinNode(source, f.asRNode(), child1.asRNode(), child2.asRNode()); + } + + @Override + public final RSyntaxNode rightJoin(final SourceSection source, final RSyntaxNode child1, final RSyntaxNode child2, final RSyntaxNode f) { + return new RRightJoinNode(source, f.asRNode(), child1.asRNode(), child2.asRNode()); + } + private static ArgumentsSignature createSignature(List<Argument<RSyntaxNode>> args) { String[] argumentNames = args.stream().map(arg -> arg.name).toArray(String[]::new); ArgumentsSignature signature = ArgumentsSignature.get(argumentNames); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RSyntaxNodeVisitor.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RSyntaxNodeVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..3e59ca741443589897aecd95ec3c58a322fe2743 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RSyntaxNodeVisitor.java @@ -0,0 +1,121 @@ +package com.oracle.truffle.r.nodes; + +import com.oracle.truffle.r.nodes.access.ConstantNode; +import com.oracle.truffle.r.nodes.access.WriteLocalFrameVariableNode; +import com.oracle.truffle.r.nodes.access.variables.LookupNode; +import com.oracle.truffle.r.nodes.builtin.InternalNode; +import com.oracle.truffle.r.nodes.control.*; +import com.oracle.truffle.r.nodes.control.IfNode; +import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; +import com.oracle.truffle.r.nodes.function.RCallNode; +import com.oracle.truffle.r.nodes.function.RCallSpecialNode; +import com.oracle.truffle.r.nodes.function.signature.MissingNode; +import com.oracle.truffle.r.nodes.query.*; +import com.oracle.truffle.r.runtime.nodes.IRSyntaxNodeVisitor; +import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; + +/** + * An interface for visitors for R Truffle nodes. + */ +public interface RSyntaxNodeVisitor<T> extends IRSyntaxNodeVisitor<T> { + public abstract T visit(final IfNode ifNode); + + public abstract T visit(final WhileNode whileNode); + + public abstract T visit(final ForNode forNode); + + public abstract T visit(final BreakNode b); + + public abstract T visit(final BlockNode block); + + public abstract T visit(final LookupNode var); + + public abstract T visit(final WriteLocalFrameVariableNode var); + + public abstract T visit(final FunctionExpressionNode fun); + + public abstract T visit(final InternalNode b); + + public abstract T visit(final RCallNode callNode); + + public abstract T visit(final RCallSpecialNode callNode); + + public abstract T visit(final ReplacementDispatchNode repl); + + public abstract T visit(final RQIRWrapperNode qir); + + public abstract T visit(final RSelectNode select); + + public abstract T visit(final RFromNode from); + + public abstract T visit(final RWhereNode where); + + public abstract T visit(final RGroupNode group); + + public abstract T visit(final ROrderNode order); + + public abstract T visit(final RJoinNode join); + + public abstract T visit(final RLeftJoinNode join); + + public abstract T visit(final RRightJoinNode join); + + public abstract T visit(final RLimitNode limit); + + public abstract T visit(final ConstantNode cst); + + public abstract T visit(final MissingNode node); + + @Override + public default T visit(final RSyntaxNode node) { + if (node instanceof IfNode) + return visit((IfNode) node); + if (node instanceof WhileNode) + return visit((WhileNode) node); + if (node instanceof ForNode) + return visit((ForNode) node); + if (node instanceof BreakNode) + return visit((BreakNode) node); + if (node instanceof BlockNode) + return visit((BlockNode) node); + if (node instanceof LookupNode) + return visit((LookupNode) node); + if (node instanceof WriteLocalFrameVariableNode) + return visit((WriteLocalFrameVariableNode) node); + if (node instanceof FunctionExpressionNode) + return visit((FunctionExpressionNode) node); + if (node instanceof InternalNode) + return visit((InternalNode) node); + if (node instanceof RCallNode) + return visit((RCallNode) node); + if (node instanceof RCallSpecialNode) + return visit((RCallSpecialNode) node); + if (node instanceof ReplacementDispatchNode) + return visit((ReplacementDispatchNode) node); + if (node instanceof RQIRWrapperNode) + return visit((RQIRWrapperNode) node); + if (node instanceof RSelectNode) + return visit((RSelectNode) node); + if (node instanceof RFromNode) + return visit((RFromNode) node); + if (node instanceof RWhereNode) + return visit((RWhereNode) node); + if (node instanceof RGroupNode) + return visit((RGroupNode) node); + if (node instanceof ROrderNode) + return visit((ROrderNode) node); + if (node instanceof RJoinNode) + return visit((RJoinNode) node); + if (node instanceof RLeftJoinNode) + return visit((RLeftJoinNode) node); + if (node instanceof RRightJoinNode) + return visit((RRightJoinNode) node); + if (node instanceof RLimitNode) + return visit((RLimitNode) node); + if (node instanceof ConstantNode) + return visit((ConstantNode) node); + if (node instanceof MissingNode) + return visit((MissingNode) node); + throw new RuntimeException("Internal error: unknown node to visit: " + node.getClass() + "."); + } +} \ No newline at end of file diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteLocalFrameVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteLocalFrameVariableNode.java index 19b3ab595db32b7160421cf956bfb64aa4e501c5..58f07b278db0aeecb981f7d3c5d9772d348343d0 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteLocalFrameVariableNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteLocalFrameVariableNode.java @@ -53,7 +53,7 @@ public abstract class WriteLocalFrameVariableNode extends BaseWriteVariableNode return WriteLocalFrameVariableNodeGen.create(name, Mode.INVISIBLE, null); } - private final Mode mode; + public final Mode mode; private final ValueProfile storedObjectProfile = ValueProfile.createClassProfile(); private final BranchProfile invalidateProfile = BranchProfile.create(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LookupNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LookupNode.java new file mode 100644 index 0000000000000000000000000000000000000000..358f657156255e6af910516015a176d0f2d1c473 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LookupNode.java @@ -0,0 +1,50 @@ +package com.oracle.truffle.r.nodes.access.variables; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; +import com.oracle.truffle.r.runtime.nodes.RSourceSectionNode; +import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup; +import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; + +public final class LookupNode extends RSourceSectionNode implements RSyntaxNode, RSyntaxLookup { + + @Child private ReadVariableNode read; + @Child private SetVisibilityNode visibility; + + LookupNode(SourceSection sourceSection, ReadVariableNode read) { + super(sourceSection); + this.read = read; + } + + @Override + public void voidExecute(VirtualFrame frame) { + read.executeInternal(frame, frame); + } + + @Override + public Object execute(VirtualFrame frame) { + return read.executeInternal(frame, frame); + } + + @Override + public Object visibleExecute(VirtualFrame frame) { + if (visibility == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + visibility = insert(SetVisibilityNode.create()); + } + visibility.execute(frame, true); + return read.executeInternal(frame, frame); + } + + @Override + public String getIdentifier() { + return read.getIdentifier(); + } + + @Override + public boolean isFunctionLookup() { + return read.isFunctionLookup(); + } +} \ No newline at end of file diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java index 338251a3ff4be1790e17ee1d2f8f6361ee9a7ca0..3db82a9b2c9413691c66c98adcb2397232c94c56 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java @@ -48,7 +48,6 @@ import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; -import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RArguments; @@ -76,51 +75,8 @@ import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor.FrameAndSlo import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor.LookupResult; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor.MultiSlotData; import com.oracle.truffle.r.runtime.nodes.RBaseNode; -import com.oracle.truffle.r.runtime.nodes.RSourceSectionNode; -import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; -final class LookupNode extends RSourceSectionNode implements RSyntaxNode, RSyntaxLookup { - - @Child private ReadVariableNode read; - @Child private SetVisibilityNode visibility; - - LookupNode(SourceSection sourceSection, ReadVariableNode read) { - super(sourceSection); - this.read = read; - } - - @Override - public void voidExecute(VirtualFrame frame) { - read.executeInternal(frame, frame); - } - - @Override - public Object execute(VirtualFrame frame) { - return read.executeInternal(frame, frame); - } - - @Override - public Object visibleExecute(VirtualFrame frame) { - if (visibility == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - visibility = insert(SetVisibilityNode.create()); - } - visibility.execute(frame, true); - return read.executeInternal(frame, frame); - } - - @Override - public String getIdentifier() { - return read.getIdentifier(); - } - - @Override - public boolean isFunctionLookup() { - return read.isFunctionLookup(); - } -} - /** * This node is used to read a variable from the local or enclosing environments. It specializes to * a particular layout of frame descriptors and enclosing environments, and re-specializes in case diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java index 1205b62c9e8c59c4854ed3b1684773021d5cb882..b66f41e9d5190bc5e5af1e36a33afe0ae0276be7 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java @@ -99,6 +99,18 @@ public final class ForNode extends AbstractLoopNode implements RSyntaxNode, RSyn return RNull.instance; } + public final RSyntaxLookup getVar() { + return var; + } + + public final RNode getRange() { + return writeRangeNode.getRhs(); + } + + public final RNode getBody() { + return ((ForRepeatingNode) loopNode.getRepeatingNode()).body; + } + private static final class ForRepeatingNode extends AbstractRepeatingNode { private final ConditionProfile conditionProfile = ConditionProfile.createCountingProfile(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java index 46906aeebc5ce7b0133ff4eef73a250d0baef3a8..719b54a06200ad11ed8fb5afeefcffed841449d4 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementDispatchNode.java @@ -55,11 +55,11 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; public final class ReplacementDispatchNode extends OperatorNode { // these are only @Child to make instrumentation work - @Child private RNode lhs; - @Child private RNode rhs; + @Child public RNode lhs; + @Child public RNode rhs; - private final boolean isSuper; - private final int tempNamesStartIndex; + public final boolean isSuper; + public final int tempNamesStartIndex; public ReplacementDispatchNode(SourceSection src, RSyntaxLookup operator, RSyntaxNode lhs, RSyntaxNode rhs, boolean isSuper, int tempNamesStartIndex) { super(src, operator); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/WhileNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/WhileNode.java index 98e84c5e61956437f0144286eb04b308d26d9104..b41dc4b0873dd05685e19b53f152348dd592d570 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/WhileNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/WhileNode.java @@ -56,6 +56,14 @@ public final class WhileNode extends AbstractLoopNode implements RSyntaxNode, RS return RNull.instance; } + public RSyntaxNode getCondition() { + return ((WhileRepeatingNode) loop.getRepeatingNode()).condition.getRSyntaxNode(); + } + + public RNode getBody() { + return ((WhileRepeatingNode) loop.getRepeatingNode()).body; + } + private static final class WhileRepeatingNode extends AbstractRepeatingNode { @Child private ConvertBooleanNode condition; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java index 2b427df2deb4d73160eed621fee45ebb0ccf1377..cb218d54517a09533e0370ebe6099d4caac134fe 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java @@ -102,7 +102,7 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo */ private String name; private SourceSection sourceSectionR; - private final SourceSection[] argSourceSections; + public final SourceSection[] argSourceSections; @Child private RNode saveArguments; @Child private FrameSlotNode onExitSlot; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java index 98a793a0147a1f032e48fafd264fc5299d5874e0..0783ed2799b0a6a1876cd6e0d6b87b6488f2b123 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallSpecialNode.java @@ -130,7 +130,7 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode private final RSyntaxNode[] arguments; private final ArgumentsSignature signature; - private final RBuiltinDescriptor expectedFunction; + public final RBuiltinDescriptor expectedFunction; private final RVisibility visible; /** @@ -376,6 +376,10 @@ public final class RCallSpecialNode extends RCallBaseNode implements RSyntaxNode return signature == null ? ArgumentsSignature.empty(1) : signature; } + public RNode getFunctionNode() { + return functionNode; + } + @Override public RSyntaxElement[] getSyntaxArguments() { return arguments == null ? new RSyntaxElement[]{RSyntaxLookup.createDummyLookup(RSyntaxNode.LAZY_DEPARSE, "...", false)} : arguments; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRInterface.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRInterface.java new file mode 100644 index 0000000000000000000000000000000000000000..d888147f80fc5d6ce4ba5b9f5e82121f5c5f86d5 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRInterface.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.qirinterface; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import com.oracle.truffle.api.frame.Frame; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.FrameSlot; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.api.vm.PolyglotEngine.Value; +import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; +import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RPromise; +import com.oracle.truffle.r.runtime.env.REnvironment; + +import qir.ast.*; +import qir.ast.data.*; +import qir.ast.expression.*; +import qir.driver.DBDriver; +import qir.driver.QIRDriver; + +public final class QIRInterface { + /** + * Runs a query in the database pointed by the given driver and returns the results. + * + * @param query The query to be executed in the targeted database + * @return The results of the query + */ + public static final Map<String, List<Object>> run(final QIRNode query) { + // Run the query and retrieve results + QIRNode qirRes = QIRDriver.run(query); + + // An error during the evaluation of the query + if (qirRes == null) + throw new RuntimeException("Could not run query: " + query); + + // The query did not return the right type + if (!(qirRes instanceof QIRList)) + throw new RuntimeException("Internal error: query returned a non-list type"); + + // The query returned an empty result + if (qirRes == QIRLnil.instance) + return new HashMap<>(); + + final Map<String, List<Object>> results = new HashMap<>(); + + // Inhabit the result columns with empty lists (we need the keys to create the lists) TODO: + // Find a way to add the first row here and skip it on the next loop + for (QIRNode firstRow = ((QIRLcons) qirRes).value; firstRow != QIRTnil.instance; firstRow = ((QIRTcons) firstRow).tail) + results.put(((QIRTcons) firstRow).id, new ArrayList<>()); + + // Process the rest of the rows TODO: Error if a row has unknown column + for (; qirRes != QIRLnil.instance; qirRes = ((QIRLcons) qirRes).tail) + for (QIRNode row = ((QIRLcons) qirRes).value; row != QIRTnil.instance; row = ((QIRTcons) row).tail) + results.get(((QIRTcons) row).id).add(QIRToRType(((QIRTcons) row).value)); + + return results; + } + + /** + * Resolves the free variables of a query. + * + * @param arg The query to be executed in the targeted database + * @param argFrame The environment of execution + * @return The closed query + */ + public static final QIRNode normalize(final QIRNode arg, final Frame argFrame) { + QIRNode query = arg; + final SourceSection dummy = Source.newBuilder("").name("QIR interface").mimeType(RRuntime.R_APP_MIME).build().createUnavailableSection(); + + for (Map<String, QIRVariable> fvs = QIRDriver.getFreeVars(query); !fvs.isEmpty(); fvs = QIRDriver.getFreeVars(query)) + for (final QIRVariable fv : fvs.values()) { + final String varName = fv.id; + Frame frame = argFrame; + FrameSlot varSlot = frame.getFrameDescriptor().findFrameSlot(varName); + for (; varSlot == null && frame.getArguments()[4] instanceof Frame && ((Frame) frame.getArguments()[4]).getArguments()[4] instanceof Frame; frame = (Frame) frame.getArguments()[4]) + varSlot = ((Frame) frame.getArguments()[4]).getFrameDescriptor().findFrameSlot(varName); + query = new QIRApply(dummy, new QIRLambda(dummy, null, new QIRVariable(dummy, varName, varSlot), query, new FrameDescriptor()), + varName.equals("interval") ? new QIRExternal(dummy, "interval") : varName.equals("having") ? new QIRExternal(dummy, "having") // TODO: + // Remove + // this + // hack + : RToQIRType(fv.sourceSection, varSlot != null ? frame.getValue(varSlot) : RContext.getInstance().lookupBuiltin(varName))); + } + return query; + } + + /** + * This function closes the connection of database drivers. + */ + public static final void closeDrivers() { + DBDriver.closeDrivers(); + } + + /** + * Translates a QIR expression into a R statement. + * + * @param value The QIR expression to translate + * @return The translation of the QIR expression in R + * @throws UnsupportedOperationException If the type of the value is not supported. + */ + @SuppressWarnings("unchecked") + static final <T> T QIRToRType(final QIRNode value) throws UnsupportedOperationException { + if (value instanceof QIRBaseValue<?>) + return ((QIRBaseValue<T>) value).value; + throw new RuntimeException("Unsupported value: " + value); + } + + /** + * Translates a R statement into a QIR expression. + * + * @param src The {@link SourceSection} of the given value + * @param value The R statement to translate + * @return The translation of the R statement in QIR + */ + static final <T> QIRNode RToQIRType(final SourceSection src, final T value) { + if (value instanceof BigInteger) + return new QIRBigNumber(src, (BigInteger) value); + if (value instanceof Long) + return new QIRNumber(src, (Long) value); + if (value instanceof Byte) + return new QIRNumber(src, (Byte) value); + if (value instanceof Double) + return new QIRDouble(src, (Double) value); + if (value instanceof Boolean) + return QIRBoolean.create((Boolean) value); + if (value instanceof String) + return new QIRString(src, (String) value); + if (value instanceof REnvironment) { + REnvironment env = (REnvironment) value; + final Object queryId = env.get("queryId"); + if (queryId != null) // The object is a query + return normalize(RContext.queries.get((Integer) queryId), RContext.envs.get((Integer) queryId)); + final String tableName = (String) env.get("tableName"); + final String schemaName = (String) env.get("schemaName"); + final String dbName = (String) env.get("dbName"); + final String configFile = (String) env.get("configFile"); + if (tableName != null && dbName != null && configFile != null) // The object is a table + return new QIRTable(src, new QIRString(null, tableName), new QIRString(null, dbName), new QIRString(null, configFile), new QIRString(null, schemaName)); + // else, the object is considered a tuple + QIRTuple tuple = QIRTnil.instance; + for (final Object x : env.getFrame().getFrameDescriptor().getIdentifiers()) + tuple = new QIRTcons(src, (String) x, RToQIRType(src, env.get((String) x)), tuple); + return tuple; + } + if (value instanceof FunctionExpressionNode) { + return RFunctionToQIRType(src, ((FunctionExpressionNode) value).getSyntaxDebugName(), (FunctionDefinitionNode) (((FunctionExpressionNode) value).getCallTarget().getRootNode())); + } + if (value instanceof RFunction) { + final RFunction fun = (RFunction) value; + switch (fun.getName()) { + case "new.env": + return new QIRLambda(src, "new.env", new QIRVariable(null, "_", null), QIRTnil.instance, new FrameDescriptor()); + case "return": + case "(": + case "query.force": { + final QIRVariable x = new QIRVariable(null, "x", null); + return new QIRLambda(src, "identity", x, x, new FrameDescriptor()); + } + case "new.tableRef": + final QIRVariable tableName = new QIRVariable(null, "__tmp__"); + final QIRVariable dbName = new QIRVariable(null, "__tmp2__"); + final QIRVariable configFile = new QIRVariable(null, "__tmp3__"); + final QIRVariable schemaName = new QIRVariable(null, "__tmp4__"); + return new QIRLambda(null, null, tableName, + new QIRLambda(null, null, dbName, new QIRLambda(null, null, configFile, + new QIRLambda(null, null, schemaName, new QIRTable(src, tableName, dbName, configFile, schemaName), + new FrameDescriptor()), + new FrameDescriptor()), + new FrameDescriptor()), + new FrameDescriptor()); + case "sum": + case "min": + case "max": + case "date": + return new QIRExternal(src, fun.getName()); + case "substr": + return new QIRExternal(src, "substring"); + case "mean": + return new QIRExternal(src, "avg"); + case "length": + return new QIRExternal(src, "count"); + case "match": + return new QIRExternal(src, "match"); + case "format": { + final QIRVariable x = new QIRVariable(null, "x", null); + final QIRVariable y = new QIRVariable(null, "y", null); + return new QIRLambda(null, null, x, new QIRLambda(null, null, y, new QIRApply(null, new QIRExternal(src, "extractYear"), x), new FrameDescriptor()), + new FrameDescriptor()); + } + case "regexpr": + final QIRVariable x = new QIRVariable(null, "x", null); + final QIRVariable y = new QIRVariable(null, "y", null); + return new QIRLambda(null, null, x, new QIRLambda(null, null, y, new QIRApply(null, new QIRApply(null, new QIRExternal(src, "like"), y), x), new FrameDescriptor()), + new FrameDescriptor()); + default: + return RFunctionToQIRType(src, fun.getName(), (FunctionDefinitionNode) fun.getRootNode()); + } + } + if (value instanceof RPromise) { + final RPromise fun = (RPromise) value; + if (fun.isEvaluated()) + return RToQIRType(src, fun.getValue()); + return RToQIRType(src, fun.getClosure().eval(fun.getFrame())); + } + throw new RuntimeException("Unsupported value: " + value); + } + + static final QIRNode execute(final String program) { + final PolyglotEngine vm = PolyglotEngine.newBuilder().config("application/x-sl", "SLEngine", null).build(); + final Source source = Source.newBuilder(program).name("mySrc").mimeType(RRuntime.R_APP_MIME).build(); + final Value v = vm.eval(source); + + if (v == null) + throw new RuntimeException("No function main() defined in SL source file." + source.getCode()); + return RToQIRType(v.getSourceLocation(), v.get()); + } + + static final QIRTruffleNode apply(final QIRTruffleNode fun, final Object arg) { + return new QIRTruffleNode(fun.sourceSection, "r", fun.executeTruffle, fun.apply, fun.code + "(" + arg + ")"); + } + + private static final QIRNode RFunctionToQIRType(final SourceSection src, final String funName, final FunctionDefinitionNode fun) { + try { + QIRNode res = ((FunctionDefinitionNode) fun.getCallTarget().getRootNode()).getBody().accept(QIRTranslateVisitor.instance); + final String[] args = ((FunctionDefinitionNode) fun.getCallTarget().getRootNode()).getSignature().getNames(); + + if (args.length == 0) + return new QIRLambda(src, funName, null, res, new FrameDescriptor()); + for (int i = args.length - 1; i >= 0; i--) + res = new QIRLambda(src, funName, new QIRVariable(null, args[i], null), res, new FrameDescriptor()); + return res; + } catch (UnsupportedOperationException e) { + final SourceSection funSrc = fun.getCallTarget().getRootNode().getSourceSection(); + // TODO: Handle dependencies + return new QIRTruffleNode(funSrc, "r", QIRInterface::execute, QIRInterface::apply, funSrc.getCode()); + } + } +} \ No newline at end of file diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRTranslateVisitor.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRTranslateVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..4b4f009e8b8e7bd372cf9ead1577afe498dfabf5 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/qirinterface/QIRTranslateVisitor.java @@ -0,0 +1,287 @@ +package com.oracle.truffle.r.nodes.qirinterface; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.nodes.RSyntaxNodeVisitor; +import com.oracle.truffle.r.nodes.access.AccessArgumentNode; +import com.oracle.truffle.r.nodes.access.ConstantNode; +import com.oracle.truffle.r.nodes.access.WriteLocalFrameVariableNode; +import com.oracle.truffle.r.nodes.access.variables.LookupNode; +import com.oracle.truffle.r.nodes.builtin.InternalNode; +import com.oracle.truffle.r.nodes.control.*; +import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; +import com.oracle.truffle.r.nodes.function.RCallNode; +import com.oracle.truffle.r.nodes.function.RCallSpecialNode; +import com.oracle.truffle.r.nodes.function.signature.MissingNode; +import com.oracle.truffle.r.nodes.query.*; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.nodes.RNode; +import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; + +import qir.ast.*; +import qir.ast.data.*; +import qir.ast.expression.QIRBoolean; +import qir.ast.expression.QIRNull; +import qir.ast.expression.QIRNumber; +import qir.ast.expression.QIRString; +import qir.ast.expression.arithmetic.*; +import qir.ast.expression.logic.*; +import qir.ast.expression.relational.*; +import qir.ast.operator.*; + +/** + * This visitor translates a {@link RNode} into a {@link QIRNode}. + */ +public final class QIRTranslateVisitor implements RSyntaxNodeVisitor<QIRNode> { + public static final QIRTranslateVisitor instance = new QIRTranslateVisitor(); + + private QIRTranslateVisitor() { + } + + private final SourceSection dummy = Source.newBuilder("").name("QIR translate").mimeType(RRuntime.R_APP_MIME).build().createUnavailableSection(); + + @Override + public final QIRNode visit(final IfNode ifNode) { + return new QIRIf(ifNode.getSourceSection(), ifNode.getCondition().asRSyntaxNode().accept(this), ifNode.getThenPart().asRSyntaxNode().accept(this), + ifNode.getElsePart().asRSyntaxNode().accept(this)); + } + + @Override + public final QIRNode visit(final WhileNode whileNode) { + return new QIRTruffleNode(whileNode.getSourceSection(), "r", QIRInterface::execute, QIRInterface::apply, whileNode.getSourceSection().getCode()); + } + + @Override + public final QIRNode visit(final ForNode forNode) { + return new QIRTruffleNode(forNode.getSourceSection(), "r", QIRInterface::execute, QIRInterface::apply, forNode.getSourceSection().getCode()); + } + + @Override + public final QIRNode visit(final BreakNode breakNode) { + return new QIRTruffleNode(breakNode.getSourceSection(), "r", QIRInterface::execute, QIRInterface::apply, breakNode.getSourceSection().getCode()); + } + + /** + * Translation of a sequence of statements. Note: This is also where the STRAD-ASSIGN rules are + * handled. + */ + @Override + public final QIRNode visit(final BlockNode block) { + QIRNode result = null; + final RNode[] children = block.getSequence(); + final int len = children.length; + + if (len == 0) // Block is empty + return QIRNull.instance; + + result = children[len - 1].asRSyntaxNode().accept(this); // The last statement of the block + /* + * In this loop, we wrap the result with the other statements of the block in reverse order + * in the way described by the STRAD-ASSIGN rules. + */ + for (int i = len - 2; i > -1; i--) { + final RNode child = children[i]; + if (child instanceof WriteLocalFrameVariableNode) { // STRAD-ASSIGN-ID + final RNode value = ((WriteLocalFrameVariableNode) child).getRhs(); + + // If the assignment value reads an argument, then we translate to a lambda. + result = new QIRLambda(dummy, null, new QIRVariable(dummy, ((WriteLocalFrameVariableNode) child).getName(), null), result, new FrameDescriptor()); + // Else we apply STRAD-ASSIGN-ID normally + if (!(value instanceof AccessArgumentNode)) + result = new QIRApply(dummy, result, value.asRSyntaxNode().accept(this)); + } else if (child instanceof ReplacementDispatchNode && ((ReplacementDispatchNode) child).lhs instanceof LookupNode) { + final RNode value = ((ReplacementDispatchNode) child).rhs; + + // If the assignment value reads an argument, then we translate to a lambda. + result = new QIRLambda(dummy, null, new QIRVariable(dummy, ((LookupNode) ((ReplacementDispatchNode) child).lhs).getIdentifier(), null), result, new FrameDescriptor()); + // Else we apply STRAD-ASSIGN-ID normally + if (!(value instanceof AccessArgumentNode)) + result = new QIRApply(dummy, result, value.asRSyntaxNode().accept(this)); + } else if (child instanceof ReplacementDispatchNode) { // STRAD-ASSIGN-FIELD and + // STRAD-ASSIGN-DOT + // TODO: Take care of STRAD-ASSIGN-DOT + // TODO: RCallSpecialNode is not necessarily a write + final ReplacementDispatchNode repl = (ReplacementDispatchNode) child; + final RCallSpecialNode lhs = (RCallSpecialNode) repl.lhs; + final LookupNode receiver = (LookupNode) lhs.getSyntaxArguments()[0]; + final ConstantNode eid = (ConstantNode) lhs.getSyntaxArguments()[1]; + final RNode value = repl.rhs; + result = new QIRApply(dummy, new QIRLambda(dummy, null, new QIRVariable(dummy, receiver.getIdentifier(), null), result, new FrameDescriptor()), + new QIRTcons(dummy, (String) eid.getValue(), value.asRSyntaxNode().accept(this), receiver.accept(this))); + } else + throw new UnsupportedOperationException("Cannot translate \"" + block.getSourceSection() + "\" to QIR: untranslatable sequence."); + } + return result; + } + + @Override + public final QIRNode visit(final LookupNode var) { + return new QIRVariable(var.getSourceSection(), var.getIdentifier(), null); + } + + @Override + public final QIRNode visit(final WriteLocalFrameVariableNode var) { + // STRAD-ASSIGN-ID should be handled in BlockNode. + throw new RuntimeException("Error in translation to QIR: should not have visited an assignment."); + } + + @Override + public final QIRNode visit(final FunctionExpressionNode fun) { + return QIRInterface.RToQIRType(fun.getSourceSection(), fun); + } + + @Override + public final QIRNode visit(final InternalNode fun) { + throw new RuntimeException("Error in translation to QIR: InternalNode unsupported."); + } + + @Override + public final QIRNode visit(final RCallNode call) { + try { + return visitBuiltin(call.getSourceSection(), ((LookupNode) call.getFunction()).getIdentifier(), + Arrays.stream(call.getArguments().getArguments()).map(arg -> arg.accept(this)).collect(Collectors.toList())); + } catch (final RuntimeException e) { + } + final QIRNode fun = call.getFunction().asRSyntaxNode().accept(this); + final RSyntaxNode[] args = call.getArguments().getArguments(); + final int nbArgs = args.length; + QIRNode res = fun; + + if (nbArgs == 0) // call is an application with no arguments + return new QIRApply(dummy, fun, null); + for (final RSyntaxNode arg : args) + res = new QIRApply(dummy, res, arg.accept(this)); + return res; + } + + @Override + public final QIRNode visit(final RCallSpecialNode call) { + return visitBuiltin(call.getSourceSection(), call.expectedFunction.getName(), + Arrays.stream(call.getSyntaxArguments()).map(arg -> ((RSyntaxNode) arg).accept(this)).collect(Collectors.toList())); + } + + private static final QIRNode visitBuiltin(final SourceSection src, final String name, final List<QIRNode> args) { + switch (name) { + case "c": + QIRList res = QIRLnil.instance; + for (int i = args.size() - 1; i >= 0; i--) + res = new QIRLcons(src, args.get(i), res); + return res; + case "$": + return new QIRTdestr(src, args.get(0), ((QIRString) args.get(1)).value); + case "+": + return QIRPlusNodeGen.create(src, args.get(0), args.get(1)); + case "-": + return QIRMinusNodeGen.create(src, args.get(0), args.get(1)); + case "*": + return QIRStarNodeGen.create(src, args.get(0), args.get(1)); + case "/": + return QIRDivNodeGen.create(src, args.get(0), args.get(1)); + case "==": + return QIREqualNodeGen.create(src, args.get(0), args.get(1)); + case "!=": + return QIRNotNodeGen.create(src, QIREqualNodeGen.create(src, args.get(0), args.get(1))); + case "&": + case "&&": + return QIRAndNodeGen.create(src, args.get(0), args.get(1)); + case "|": + case "||": + return QIROrNodeGen.create(src, args.get(0), args.get(1)); + case "<=": + return QIRLowerOrEqualNodeGen.create(src, args.get(0), args.get(1)); + case "<": + return QIRLowerThanNodeGen.create(src, args.get(0), args.get(1)); + case ">=": + return QIRNotNodeGen.create(src, QIRLowerThanNodeGen.create(src, args.get(0), args.get(1))); + case ">": + return QIRNotNodeGen.create(src, QIRLowerOrEqualNodeGen.create(src, args.get(0), args.get(1))); + case "!": + return QIRNotNodeGen.create(src, args.get(0)); + case "(": + if (args.size() == 1) + return args.get(0); + default: + throw new RuntimeException("Unknown call special node: " + name); + } + } + + @Override + public final QIRNode visit(final ReplacementDispatchNode repl) { + // STRAD-ASSIGN-FIELD and STRAD-ASSIGN-DOT should be handled in BlockNode. + throw new RuntimeException("Error in translation to QIR: should not have visited an assignment."); + } + + /** + * Translation of a subquery. + */ + @Override + public final QIRNode visit(final RQIRWrapperNode query) { + return RContext.queries.get(query.id); + } + + @Override + public final QIRNode visit(final RSelectNode select) { + return new QIRProject(select.getSourceSection(), select.formatter.asRSyntaxNode().accept(this), select.query.asRSyntaxNode().accept(this)); + } + + @Override + public final QIRNode visit(final RFromNode from) { + return new QIRScan(from.getSourceSection(), from.getTable().asRSyntaxNode().accept(this)); + } + + @Override + public final QIRNode visit(final RWhereNode where) { + return new QIRFilter(where.getSourceSection(), where.getFilter().asRSyntaxNode().accept(this), where.getQuery().asRSyntaxNode().accept(this)); + } + + @Override + public final QIRNode visit(final RGroupNode group) { + return new QIRGroupBy(group.getSourceSection(), group.getGroup().asRSyntaxNode().accept(this), group.getQuery().asRSyntaxNode().accept(this)); + } + + @Override + public final QIRNode visit(final ROrderNode order) { + QIRNode f = order.getIsAscending().asRSyntaxNode().accept(this); + + for (QIRNode l = ((QIRLambda) f).body; l instanceof QIRLcons; l = ((QIRLcons) l).tail) + ((QIRLcons) l).value = QIRBoolean.create(((QIRLcons) l).value.equals(new QIRNumber(null, 1))); + return new QIRSortBy(order.getSourceSection(), order.getOrder().asRSyntaxNode().accept(this), f, + order.getQuery().asRSyntaxNode().accept(this)); + } + + @Override + public final QIRNode visit(final RJoinNode join) { + return new QIRJoin(join.getSourceSection(), join.getFilter().asRSyntaxNode().accept(this), join.getLeft().asRSyntaxNode().accept(this), join.getRight().asRSyntaxNode().accept(this)); + } + + @Override + public final QIRNode visit(final RLeftJoinNode join) { + return new QIRLeftJoin(join.getSourceSection(), join.getFilter().asRSyntaxNode().accept(this), join.getLeft().asRSyntaxNode().accept(this), join.getRight().asRSyntaxNode().accept(this)); + } + + @Override + public final QIRNode visit(final RRightJoinNode join) { + return new QIRRightJoin(join.getSourceSection(), join.getFilter().asRSyntaxNode().accept(this), join.getLeft().asRSyntaxNode().accept(this), join.getRight().asRSyntaxNode().accept(this)); + } + + @Override + public final QIRNode visit(final RLimitNode limit) { + return new QIRLimit(limit.getSourceSection(), limit.getLimit().asRSyntaxNode().accept(this), limit.getQuery().asRSyntaxNode().accept(this)); + } + + @Override + public final QIRNode visit(final ConstantNode cst) { + return QIRInterface.RToQIRType(cst.getSourceSection(), cst.getValue()); + } + + @Override + public final QIRNode visit(final MissingNode node) { + throw new RuntimeException("Cannot translate MissingNode to QIR."); + } +} \ No newline at end of file diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RFromNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RFromNode.java new file mode 100644 index 0000000000000000000000000000000000000000..fb2bb93612deccc8565e21d9a7cc5593971c970b --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RFromNode.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.query; + +import com.oracle.truffle.api.nodes.NodeInfo; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.nodes.RNode; + +@NodeInfo(shortName = "From") +public final class RFromNode extends RQueryNode { + @Child private RNode table; + + public RFromNode(final SourceSection src, final RNode table) { + super(src); + this.table = table; + } + + public final RNode getTable() { + return table; + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RGroupNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RGroupNode.java new file mode 100644 index 0000000000000000000000000000000000000000..4cdbb523b3613c25370860ff64cd936c9942ea66 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RGroupNode.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.query; + +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.nodes.RNode; + +@NodeInfo(shortName = "GroupBy") +public final class RGroupNode extends RQueryNode { + @Child private RNode group; + @Child private RNode query; + + public RGroupNode(final SourceSection src, final RNode group, final RNode query) { + super(src); + this.group = group; + this.query = query; + } + + public final RNode getGroup() { + return group; + } + + public final RNode getQuery() { + return query; + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RJoinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RJoinNode.java new file mode 100644 index 0000000000000000000000000000000000000000..8aedec3a3b4a48b251a3ff7dc064081307e11273 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RJoinNode.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.query; + +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.nodes.RNode; + +@NodeInfo(shortName = "Join") +public final class RJoinNode extends RQueryNode { + @Child private RNode filter; + @Child private RNode left; + @Child private RNode right; + + public RJoinNode(final SourceSection src, final RNode filter, final RNode left, final RNode right) { + super(src); + this.filter = filter; + this.left = left; + this.right = right; + } + + public final RNode getFilter() { + return filter; + } + + public final RNode getLeft() { + return left; + } + + public final RNode getRight() { + return right; + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RLeftJoinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RLeftJoinNode.java new file mode 100644 index 0000000000000000000000000000000000000000..797eacb8714b8bea0628bb6537f273cafd6e0a42 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RLeftJoinNode.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.query; + +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.nodes.RNode; + +@NodeInfo(shortName = "Join") +public final class RLeftJoinNode extends RQueryNode { + @Child private RNode filter; + @Child private RNode left; + @Child private RNode right; + + public RLeftJoinNode(final SourceSection src, final RNode filter, final RNode left, final RNode right) { + super(src); + this.filter = filter; + this.left = left; + this.right = right; + } + + public final RNode getFilter() { + return filter; + } + + public final RNode getLeft() { + return left; + } + + public final RNode getRight() { + return right; + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RLimitNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RLimitNode.java new file mode 100644 index 0000000000000000000000000000000000000000..1fe4d66f4fdbbdf821319d6d196e05d9fce80b11 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RLimitNode.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.query; + +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.nodes.RNode; + +@NodeInfo(shortName = "Limit") +public final class RLimitNode extends RQueryNode { + @Child private RNode limit; + @Child private RNode query; + + public RLimitNode(final SourceSection src, final RNode limit, final RNode query) { + super(src); + this.limit = limit; + this.query = query; + } + + public final RNode getLimit() { + return limit; + } + + public final RNode getQuery() { + return query; + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/ROrderNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/ROrderNode.java new file mode 100644 index 0000000000000000000000000000000000000000..b6a50d4d1b060e6f7e5c378ea4981ac14b1b7091 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/ROrderNode.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.query; + +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.nodes.RNode; + +@NodeInfo(shortName = "OrderBy") +public final class ROrderNode extends RQueryNode { + @Child private RNode order; + @Child private RNode isAscending; + @Child private RNode query; + + public ROrderNode(final SourceSection src, final RNode order, final RNode isAscending, final RNode query) { + super(src); + this.order = order; + this.isAscending = isAscending; + this.query = query; + } + + public final RNode getOrder() { + return order; + } + + public final RNode getIsAscending() { + return isAscending; + } + + public final RNode getQuery() { + return query; + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQIRWrapperNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQIRWrapperNode.java new file mode 100644 index 0000000000000000000000000000000000000000..31d954defdac50402052c378ac0a7cb0bdbb36e4 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQIRWrapperNode.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.query; + +import com.oracle.truffle.api.CompilerDirectives.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.env.REnvironment.PutException; +import com.oracle.truffle.r.runtime.nodes.RSourceSectionNode; +import com.oracle.truffle.r.runtime.nodes.RSyntaxElement; +import com.oracle.truffle.r.runtime.nodes.RSyntaxFunction; + +@NodeInfo(shortName = "query", description = "The node representing a query") +public final class RQIRWrapperNode extends RSourceSectionNode implements RSyntaxFunction { + // The unique identifier of the query + public final int id; + + public RQIRWrapperNode(final SourceSection src) { + super(src); + this.id = RContext.createFreshQuery(); + } + + @Override + public final REnvironment execute(VirtualFrame frame) { + final int instanceId = RContext.envs.get(id) == null ? id : RContext.createFreshQueryFrom(id); + RContext.envs.set(instanceId, frame); + return createQuery(instanceId); + } + + @TruffleBoundary + private static final REnvironment createQuery(int instanceId) { + final REnvironment res = RDataFactory.createNewEnv(null); + try { + res.put("queryId", instanceId); + } catch (PutException e) { + e.printStackTrace(); + return null; + } + return res; + } + + @Override + public ArgumentsSignature getSyntaxSignature() { + return null; + } + + @Override + public RSyntaxElement[] getSyntaxArgumentDefaults() { + return new RSyntaxElement[0]; + } + + @Override + public RSyntaxElement getSyntaxBody() { + return this; + } + + @Override + public String getSyntaxDebugName() { + return getSourceSection().getCode(); + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryNode.java new file mode 100644 index 0000000000000000000000000000000000000000..2697e2f79f472f4914011975a1bdedc8941b876a --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryNode.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.query; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.NodeInfo; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.nodes.RSourceSectionNode; + +@NodeInfo(shortName = "Query") +public abstract class RQueryNode extends RSourceSectionNode { + public RQueryNode(final SourceSection src) { + super(src); + } + + @Override + public final DynamicObject execute(final VirtualFrame frame) { + throw new RuntimeException("We should not execute a RQueryNode directly."); + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryVisitor.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..a0fcc33f2020d5fa84059531bd73cb397fb476f6 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RQueryVisitor.java @@ -0,0 +1,179 @@ +package com.oracle.truffle.r.nodes.query; + +import java.util.Arrays; + +import com.oracle.truffle.r.nodes.RSyntaxNodeVisitor; +import com.oracle.truffle.r.nodes.access.ConstantNode; +import com.oracle.truffle.r.nodes.access.WriteLocalFrameVariableNode; +import com.oracle.truffle.r.nodes.access.variables.LookupNode; +import com.oracle.truffle.r.nodes.builtin.InternalNode; +import com.oracle.truffle.r.nodes.control.*; +import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; +import com.oracle.truffle.r.nodes.function.RCallNode; +import com.oracle.truffle.r.nodes.function.RCallSpecialNode; +import com.oracle.truffle.r.nodes.function.signature.MissingNode; +import com.oracle.truffle.r.nodes.qirinterface.QIRTranslateVisitor; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.nodes.RNode; +import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; + +import qir.ast.QIRNode; + +/** + * This visitor detects queries in a R statement and calls {@link QIRTranslateVisitor} to translate + * them into {@link QIRNode}. + */ +public final class RQueryVisitor implements RSyntaxNodeVisitor<RSyntaxNode> { + public static final RQueryVisitor instance = new RQueryVisitor(); + + private RQueryVisitor() { + } + + @Override + public final RSyntaxNode visit(final IfNode ifNode) { + return new IfNode(ifNode.getSourceSection(), ifNode.getSyntaxLHS(), ifNode.getCondition().asRSyntaxNode().accept(this), ifNode.getThenPart().asRSyntaxNode().accept(this), + ifNode.getElsePart() == null ? null : ifNode.getElsePart().asRSyntaxNode().accept(this)); + } + + @Override + public final RSyntaxNode visit(final WhileNode whileNode) { + return new WhileNode(whileNode.getSourceSection(), whileNode.getSyntaxLHS(), whileNode.getCondition().accept(this), whileNode.getBody().asRSyntaxNode().accept(this)); + } + + @Override + public final RSyntaxNode visit(final ForNode forNode) { + final RNode range = forNode.getRange(); + return range == null ? forNode : new ForNode(forNode.getSourceSection(), forNode.getSyntaxLHS(), forNode.getVar(), range.asRSyntaxNode().accept(this).asRNode(), + forNode.getBody().asRSyntaxNode().accept(this).asRNode()); + } + + @Override + public final RSyntaxNode visit(final BreakNode breakNode) { + return breakNode; + } + + @Override + public final RSyntaxNode visit(final BlockNode block) { + final RNode[] children = block.getSequence(); + + for (int i = 0; i < children.length; i++) + children[i] = children[i].asRSyntaxNode().accept(this).asRNode(); + return block; + } + + @Override + public final RSyntaxNode visit(final LookupNode var) { + return var; + } + + @Override + public final RSyntaxNode visit(final WriteLocalFrameVariableNode var) { + return WriteLocalFrameVariableNode.create(var.getName(), var.mode, var.getRhs().asRSyntaxNode().accept(this).asRNode()).asRSyntaxNode(); + } + + @Override + public final RSyntaxNode visit(final FunctionExpressionNode fun) { + return fun; + } + + @Override + public final RSyntaxNode visit(final InternalNode fun) { + return fun; + } + + @Override + public final RSyntaxNode visit(final RCallNode call) { + return RCallNode.createCall(call.getSourceSection(), call.getFunction().asRSyntaxNode().accept(this).asRNode(), call.getSyntaxSignature(), + Arrays.asList(call.getArguments().getArguments()).stream().map(arg -> arg.accept(this)).toArray(RSyntaxNode[]::new)); + } + + @Override + public final RSyntaxNode visit(final RCallSpecialNode call) { + return RCallSpecialNode.createCall(call.getSourceSection(), call.getFunctionNode().asRSyntaxNode().accept(this).asRNode(), call.getSyntaxSignature(), + Arrays.asList((RSyntaxNode[]) call.getSyntaxArguments()).stream().map(arg -> arg.accept(this)).toArray(RSyntaxNode[]::new)); + } + + @Override + public final RSyntaxNode visit(final ReplacementDispatchNode repl) { + return new ReplacementDispatchNode(repl.getSourceSection(), repl.getSyntaxLHS(), repl.lhs.asRSyntaxNode().accept(this), repl.rhs.asRSyntaxNode().accept(this), repl.isSuper, + repl.tempNamesStartIndex); + } + + @Override + public final RSyntaxNode visit(final RQIRWrapperNode qir) { + return qir; + } + + @Override + public final RSyntaxNode visit(final RSelectNode select) { + final RQIRWrapperNode res = new RQIRWrapperNode(select.getSourceSection()); + RContext.queries.set(res.id, select.accept(QIRTranslateVisitor.instance)); + return res; + } + + @Override + public final RSyntaxNode visit(final RFromNode from) { + final RQIRWrapperNode res = new RQIRWrapperNode(from.getSourceSection()); + RContext.queries.set(res.id, from.accept(QIRTranslateVisitor.instance)); + return res; + } + + @Override + public final RSyntaxNode visit(final RWhereNode where) { + final RQIRWrapperNode res = new RQIRWrapperNode(where.getSourceSection()); + RContext.queries.set(res.id, where.accept(QIRTranslateVisitor.instance)); + return res; + } + + @Override + public final RSyntaxNode visit(final RGroupNode group) { + final RQIRWrapperNode res = new RQIRWrapperNode(group.getSourceSection()); + RContext.queries.set(res.id, group.accept(QIRTranslateVisitor.instance)); + return res; + } + + @Override + public final RSyntaxNode visit(final ROrderNode order) { + final RQIRWrapperNode res = new RQIRWrapperNode(order.getSourceSection()); + RContext.queries.set(res.id, order.accept(QIRTranslateVisitor.instance)); + return res; + } + + @Override + public final RSyntaxNode visit(final RJoinNode join) { + final RQIRWrapperNode res = new RQIRWrapperNode(join.getSourceSection()); + RContext.queries.set(res.id, join.accept(QIRTranslateVisitor.instance)); + return res; + } + + @Override + public final RSyntaxNode visit(final RLeftJoinNode join) { + final RQIRWrapperNode res = new RQIRWrapperNode(join.getSourceSection()); + RContext.queries.set(res.id, join.accept(QIRTranslateVisitor.instance)); + return res; + } + + @Override + public final RSyntaxNode visit(final RRightJoinNode join) { + final RQIRWrapperNode res = new RQIRWrapperNode(join.getSourceSection()); + RContext.queries.set(res.id, join.accept(QIRTranslateVisitor.instance)); + return res; + } + + @Override + public final RSyntaxNode visit(final RLimitNode limit) { + final RQIRWrapperNode res = new RQIRWrapperNode(limit.getSourceSection()); + RContext.queries.set(res.id, limit.accept(QIRTranslateVisitor.instance)); + return res; + } + + @Override + public final RSyntaxNode visit(final ConstantNode cst) { + return ConstantNode.create(cst.getSourceSection(), cst.getValue()); + } + + @Override + public final RSyntaxNode visit(final MissingNode node) { + return node; + } +} \ No newline at end of file diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RRightJoinNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RRightJoinNode.java new file mode 100644 index 0000000000000000000000000000000000000000..8c5e290e2ea9d15c9e5a4aa14e4ec5474ae9707d --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RRightJoinNode.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.query; + +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.nodes.RNode; + +@NodeInfo(shortName = "Join") +public final class RRightJoinNode extends RQueryNode { + @Child private RNode filter; + @Child private RNode left; + @Child private RNode right; + + public RRightJoinNode(final SourceSection src, final RNode filter, final RNode left, final RNode right) { + super(src); + this.filter = filter; + this.left = left; + this.right = right; + } + + public final RNode getFilter() { + return filter; + } + + public final RNode getLeft() { + return left; + } + + public final RNode getRight() { + return right; + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RSelectNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RSelectNode.java new file mode 100644 index 0000000000000000000000000000000000000000..cea4032ec106f81aaf506a5a0fce97cbb7e99dc2 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RSelectNode.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.query; + +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.nodes.RNode; + +@NodeInfo(shortName = "Select") +public final class RSelectNode extends RQueryNode { + @Child public RNode formatter; + @Child public RNode query; + + public RSelectNode(final SourceSection src, final RNode formatter, final RNode query) { + super(src); + this.formatter = formatter; + this.query = query; + } + + public final RNode getFormatter() { + return formatter; + } + + public final RNode getQuery() { + return query; + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RWhereNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RWhereNode.java new file mode 100644 index 0000000000000000000000000000000000000000..386cc2343711272e292c77bc063a550c7fe6f5d0 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/query/RWhereNode.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.query; + +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.nodes.RNode; + +@NodeInfo(shortName = "Where") +public final class RWhereNode extends RQueryNode { + @Child private RNode filter; + @Child private RNode query; + + public RWhereNode(final SourceSection src, final RNode filter, final RNode query) { + super(src); + this.filter = filter; + this.query = query; + } + + public final RNode getFilter() { + return filter; + } + + public final RNode getQuery() { + return query; + } +} diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g index bc0af11a7ac5e645ae0f930cdceb4b535ae59d9a..0eac340fe02739f7edcdfcf838eaabcff4a8e361 100644 --- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g +++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g @@ -262,7 +262,7 @@ script returns [List<T> v] throw new RecognitionException(input); } } - : n_ ( s=statement { $v.add($s.v); })* + : n_ ( s=statement { $v.add(builder.handleQueries($s.v)); })* ; root_function [String name] returns [RootCallTarget v] @@ -275,7 +275,7 @@ root_function [String name] returns [RootCallTarget v] throw RInternalError.shouldNotReachHere("not at EOF after parsing deserialized function"); } } - : n_ op=FUNCTION n_ LPAR n_ (par_decl[params] (n_ COMMA n_ par_decl[params])* n_)? RPAR n_ body=expr_or_assign { $v = builder.rootFunction(language, src($op, last()), params, $body.v, name); } + : n_ op=FUNCTION n_ LPAR n_ (par_decl[params] (n_ COMMA n_ par_decl[params])* n_)? RPAR n_ body=expr_or_assign { $v = builder.rootFunction(language, src($op, last()), params, builder.handleQueries($body.v), name); } ; statement returns [T v] @@ -356,7 +356,7 @@ repeat_expr returns [T v] function [T assignedTo] returns [T v] @init { List<Argument<T>> params = new ArrayList<>(); } - : op=FUNCTION n_ LPAR n_ (par_decl[params] (n_ COMMA n_ par_decl[params])* n_)? RPAR n_ body=expr_or_assign { $v = builder.function(language, src($op, last()), params, $body.v, assignedTo); } + : op=FUNCTION n_ LPAR n_ (par_decl[params] (n_ COMMA n_ par_decl[params])* n_)? RPAR n_ body=expr_or_assign { $v = builder.function(language, src($op, last()), params, builder.handleQueries($body.v), assignedTo); } ; par_decl [List<Argument<T>> l] @@ -501,7 +501,19 @@ simple_expr returns [T v] | op=LPAR n_ ea=expr_or_assign n_ y=RPAR { $v = builder.call(src($op, $y), operator($op), $ea.v); } | s=sequence { $v = $s.v; } | e=expr_wo_assign { $v = $e.v; } + | q=query { $v = $q.v; } ; + +query returns [T v] + : op=SELECT n_ LPAR n_ formatter=expr n_ COMMA n_ child=expr end=RPAR { $v = builder.select(src($op, $end), $formatter.v, $child.v); } + | op=FROM n_ LPAR n_ child=expr end=RPAR { $v = builder.from(src($op, $end), $child.v); } + | op=WHERE n_ LPAR n_ filter=expr n_ COMMA n_ child=expr end=RPAR { $v = builder.where(src($op, $end), $filter.v, $child.v); } + | op=GROUP n_ LPAR n_ group=expr n_ COMMA n_ child=expr end=RPAR { $v = builder.groupby(src($op, $end), $group.v, $child.v); } + | op=ORDER n_ LPAR n_ order=expr n_ COMMA n_ asc=expr COMMA n_ child=expr end=RPAR { $v = builder.orderby(src($op, $end), $order.v, $asc.v, $child.v); } + | op=JOIN n_ LPAR n_ child1=expr n_ COMMA n_ child2=expr COMMA n_ f=expr end=RPAR { $v = builder.join(src($op, $end), $child1.v, $child2.v, $f.v); } + | op=LJOIN n_ LPAR n_ child1=expr n_ COMMA n_ child2=expr COMMA n_ f=expr end=RPAR { $v = builder.leftJoin(src($op, $end), $child1.v, $child2.v, $f.v); } + | op=RJOIN n_ LPAR n_ child1=expr n_ COMMA n_ child2=expr COMMA n_ f=expr end=RPAR { $v = builder.rightJoin(src($op, $end), $child1.v, $child2.v, $f.v); } + ; number returns [T v] : i=INTEGER { @@ -656,6 +668,14 @@ IF : 'if' ; ELSE : 'else' ; NEXT : 'next' ; BREAK : 'break' ; +SELECT : 'query.select' ; +FROM : 'query.from' ; +WHERE : 'query.where' ; +GROUP : 'query.group' ; +ORDER : 'query.order' ; +JOIN : 'query.join' ; +LJOIN : 'query.leftJoin' ; +RJOIN : 'query.rightJoin' ; WS : ('\u0009'|'\u0020'|'\u00A0') { $channel=HIDDEN; } ; NEWLINE : LINE_BREAK { if(incompleteNesting > 0) $channel=HIDDEN; } ; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/LazyResourceHandlerFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/LazyResourceHandlerFactory.java index 649c8a0e75539d024400ba2656fed85353fe6ad6..8a4d0411ca3e27e61f7f1f3e537f332a81d0fa3f 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/LazyResourceHandlerFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/LazyResourceHandlerFactory.java @@ -24,18 +24,22 @@ package com.oracle.truffle.r.runtime; import java.io.BufferedReader; import java.io.File; +import java.io.FilePermission; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; import java.security.CodeSource; +import java.security.Permissions; +import java.security.ProtectionDomain; +import java.security.cert.Certificate; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; - import com.oracle.truffle.r.runtime.ResourceHandlerFactory.Handler; /** @@ -58,9 +62,21 @@ class LazyResourceHandlerFactory extends ResourceHandlerFactory implements Handl return this; } + public static final ProtectionDomain getHack() { + Certificate[] certs = null; + Permissions permissions = new Permissions(); + permissions.add(new FilePermission("file:/home/julien/eclipse/workspace/R.jar", "read")); + permissions.add(new FilePermission("file:/home/julien/eclipse/workspace/phd/fastr", "read")); + try { + return new ProtectionDomain(new CodeSource(new URL("file:/home/julien/eclipse/workspace/R.jar"), certs), permissions); + } catch (MalformedURLException e1) { + throw new RuntimeException("Bad domain"); + } + } + @Override public Map<String, String> getRFiles(Class<?> accessor, String pkgName) { - CodeSource source = accessor.getProtectionDomain().getCodeSource(); + CodeSource source = getHack().getCodeSource(); Map<String, String> result = new HashMap<>(); try { URL url = source.getLocation(); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java index 232be3ac2c2b6d253c73b978cd4af0a56b4b8fee..7fc6adfb489daaed45702ccd49b5db62b783c134 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java @@ -177,12 +177,14 @@ public final class REnvVars implements RContext.ContextState { public static String rHome() { if (rHome == null) { rHome = System.getenv(R_HOME); + rHome = "/home/julien/eclipse/workspace/phd/fastr"; Path rHomePath; if (rHome == null) { rHomePath = getRHomePath(); } else { rHomePath = Paths.get(rHome); } + rHomePath = Paths.get(rHome); if (!validateRHome(rHomePath, markerFile())) { Utils.rSuicide("R_HOME is not set correctly"); } @@ -191,7 +193,7 @@ public final class REnvVars implements RContext.ContextState { return rHome; } - private static CodeSource codeSource = REnvVars.class.getProtectionDomain().getCodeSource(); + private static CodeSource codeSource = LazyResourceHandlerFactory.getHack().getCodeSource(); /** * In the case where {@code R_HOME} is not set, which should only occur when FastR is invoked 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.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java index e229eb4c45359b8f129193e759f89db870ad906b..5a94cb1380634e9d42b98d7c91fbe30eeee9d416 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.runtime.context; +import java.util.ArrayList; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; @@ -39,7 +40,6 @@ import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; import java.util.List; @@ -58,6 +58,7 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.TruffleContext; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.TruffleLanguage.Env; +import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.AllocationReporter; import com.oracle.truffle.api.instrumentation.Instrumenter; import com.oracle.truffle.api.interop.ForeignAccess; @@ -93,6 +94,7 @@ import com.oracle.truffle.r.runtime.conn.ConnectionSupport; import com.oracle.truffle.r.runtime.conn.StdConnections; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RTruffleObject; import com.oracle.truffle.r.runtime.env.REnvironment; @@ -103,6 +105,8 @@ import com.oracle.truffle.r.runtime.nodes.RCodeBuilder; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; import com.oracle.truffle.r.runtime.rng.RRNG; +import qir.ast.QIRNode; + /** * Encapsulates the runtime state ("context") of an R session. All access to that state from the * implementation <b>must</b> go through this class. There can be multiple instances @@ -121,6 +125,38 @@ import com.oracle.truffle.r.runtime.rng.RRNG; * Contexts can be destroyed */ public final class RContext implements RTruffleObject { + private static int queryId = 0; + public static final int INVALID_QUERY_ID = -1; + // Static representation of queries. + public static final List<QIRNode> queries = new ArrayList<>(); + public static final List<VirtualFrame> envs = new ArrayList<>(); + // A query returns a vector of tuples. A tuple is a map from a column name to a value. + public static final List<RList> results = new ArrayList<>(); + + /** + * Returns a fresh identifier for a query. + * + * @return A unique query identifier + */ + public static int createFreshQuery() { + queries.add(null); + envs.add(null); + results.add(null); + return queryId++; + } + + /** + * Returns a fresh identifier for the given query. + * + * @param id The identifier of the query. + * @return A unique query identifier + */ + public static int createFreshQueryFrom(int id) { + queries.add(queries.get(id)); + envs.add(null); + results.add(null); + return queryId++; + } public static final int CONSOLE_WIDTH = 80; @@ -291,6 +327,8 @@ public final class RContext implements RTruffleObject { */ private static boolean embedded; + private static boolean deepEmbedded; + /* * Workarounds to finesse project circularities between runtime/nodes. */ @@ -371,6 +409,15 @@ public final class RContext implements RTruffleObject { return embedded; } + public static void setDeepEmbedded() { + deepEmbedded = true; + embedded = true; + } + + public static boolean isDeepEmbedded() { + return deepEmbedded; + } + /** * Sets the fields that do not depend on complex initialization. * @@ -487,7 +534,9 @@ public final class RContext implements RTruffleObject { stateDLL.initialize(this); stateRFFI = RFFIFactory.getInstance().newContextState(); // separate in case initialize calls getStateRFFI()! - stateRFFI.initialize(this); + + if (!deepEmbedded) + stateRFFI.initialize(this); if (!embedded) { doEnvOptionsProfileInitialization(); @@ -497,7 +546,8 @@ public final class RContext implements RTruffleObject { stateRErrorHandling.initialize(this); stateRConnection.initialize(this); stateStdConnections.initialize(this); - stateRNG.initialize(this); + if (!deepEmbedded) + stateRNG.initialize(this); stateRSerialize.initialize(this); stateLazyDBCache.initialize(this); stateInstrumentation.initialize(this); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IRSyntaxNodeVisitor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IRSyntaxNodeVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..1b175cb2dccbacfaff8b9cbccd7114f473777ed6 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IRSyntaxNodeVisitor.java @@ -0,0 +1,5 @@ +package com.oracle.truffle.r.runtime.nodes; + +public interface IRSyntaxNodeVisitor<T> { + public abstract T visit(final RSyntaxNode node); +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java index 3eaed47f55b88159cd36daa8df6e9feac6ecac1d..8fcd0952d9242aa7c254c254d48d719c99a0e8d6 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java @@ -96,6 +96,51 @@ public interface RCodeBuilder<T> { */ T call(SourceSection source, T lhs, List<Argument<T>> arguments); + /** + * Processes queries in an expression to make them ready for evaluation. + */ + T handleQueries(final T expression); + + /** + * Creates a select query. + */ + T select(final SourceSection source, final T formatter, final T child); + + /** + * Creates a from query. + */ + T from(final SourceSection source, final T child); + + /** + * Creates a where query. + */ + T where(final SourceSection source, final T filter, final T child); + + /** + * Creates a group by query. + */ + T groupby(final SourceSection source, final T group, final T child); + + /** + * Creates an order by query. + */ + T orderby(final SourceSection source, final T order, final T asc, final T child); + + /** + * Creates a join query. + */ + T join(final SourceSection source, final T child1, final T child2, final T f); + + /** + * Creates a left join query. + */ + T leftJoin(final SourceSection source, final T child1, final T child2, final T f); + + /** + * Creates a right join query. + */ + T rightJoin(final SourceSection source, final T child1, final T child2, final T f); + /** * Creates a constant, the value is expected to be one of FastR's scalar types (byte, int, * double, RComplex, String, RNull). @@ -157,6 +202,8 @@ public interface RCodeBuilder<T> { @Override protected T visit(RSyntaxFunction element) { + if (element.getSyntaxBody() == element) + return (T) element; ArrayList<Argument<T>> params = createArguments(element.getSyntaxSignature(), element.getSyntaxArgumentDefaults()); return function(RContext.getInstance().getLanguage(), element.getLazySourceSection(), params, accept(element.getSyntaxBody()), element.getSyntaxDebugName()); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxNode.java index 6cd0441293d5f54cdf1c5fa586872a1dc7fb769d..237803da857b684bfbc1b2f33f907c232bf164ce 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxNode.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxNode.java @@ -97,6 +97,10 @@ public interface RSyntaxNode extends RSyntaxElement { */ SourceSection LAZY_DEPARSE = RSource.createUnknown("lazy deparse"); + public default <T> T accept(final IRSyntaxNodeVisitor<T> visitor) { + return visitor.visit(this); + } + static boolean isInternal(SourceSection sourceSection) { if (sourceSection == RSyntaxNode.INTERNAL) { return true; diff --git a/com.oracle.truffle.r.test/oracle.config b/com.oracle.truffle.r.test/oracle.config new file mode 100644 index 0000000000000000000000000000000000000000..676cc848c308c0a9303477005ca673d05b3017a8 --- /dev/null +++ b/com.oracle.truffle.r.test/oracle.config @@ -0,0 +1,5 @@ +host = myoracle.com +sid = myview +port = 7658 +user = julilope +passwd = Pa$$w0rd diff --git a/com.oracle.truffle.r.test/postgre.config b/com.oracle.truffle.r.test/postgre.config new file mode 100644 index 0000000000000000000000000000000000000000..39dd278151eb10c99d66e7b091e5d6c342b355b4 --- /dev/null +++ b/com.oracle.truffle.r.test/postgre.config @@ -0,0 +1,5 @@ +host = localhost +sid = postgres +port = 5432 +user = julien +passwd = Pa$$w0rd diff --git a/com.oracle.truffle.r.test/postgre2.config b/com.oracle.truffle.r.test/postgre2.config new file mode 100644 index 0000000000000000000000000000000000000000..8ef8ed55fbf64fc1ac673aa5f1ce3e526d6fb55f --- /dev/null +++ b/com.oracle.truffle.r.test/postgre2.config @@ -0,0 +1,5 @@ +host = localhost +sid = other +port = 5432 +user = julien +passwd = Pa$$w0rd diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/RTestSuite.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/RTestSuite.java new file mode 100644 index 0000000000000000000000000000000000000000..52734b9528e3223e862314c5b7d126eaa2ed2934 --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/RTestSuite.java @@ -0,0 +1,62 @@ +package com.oracle.truffle.r.test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; + +import com.oracle.truffle.r.launcher.RscriptCommand; + +/** + * This class runs FastR on every R file it can find in given directories (it will search + * recursively). + */ +public final class RTestSuite { + private static final String defaultTestsDirectory = "tests"; + + public static final void main(String[] args) { + final AtomicInteger successfulTests = new AtomicInteger(0); + final AtomicInteger totalTests = new AtomicInteger(0); + + Arrays.asList(args.length == 0 ? new String[]{defaultTestsDirectory} : args).stream().map( + dir -> { + try { + return Files.find(Paths.get(dir), 50, + (p, bfa) -> (p.toString().endsWith(".R") || p.toString().endsWith(".r")) && bfa.isRegularFile() && !p.toString().startsWith("tests/tpch/")); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + }).flatMap(x -> x).forEach(file -> { + System.out.println("Testing: " + file); + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final String expected; + try { + expected = String.join("\n", Files.readAllLines(Paths.get(file.toString().replaceFirst("\\.[Rr]", ".out")))); + RscriptCommand.doMain(new String[]{"Rscript", file.toString()}, null, System.in, new PrintStream(baos), System.err); + if (expected.equals(baos.toString())) + successfulTests.incrementAndGet(); + else { + System.out.println("[FAILED] Expected: "); + System.out.println(expected); + System.out.println("got: "); + System.out.println(baos.toString()); + } + } catch (IOException e) { + System.err.println("[FAILED] Could not find expected output."); + } + System.out.flush(); + System.err.flush(); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + totalTests.incrementAndGet(); + }); + System.out.println("Passed " + successfulTests + "/" + totalTests + " tests."); + } +} diff --git a/com.oracle.truffle.r.test/tests/QueryJoinCrossDatabases.R b/com.oracle.truffle.r.test/tests/QueryJoinCrossDatabases.R new file mode 100644 index 0000000000000000000000000000000000000000..37f46f7c340c09b00a943e9a7e705988d202d6f4 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/QueryJoinCrossDatabases.R @@ -0,0 +1,10 @@ +emp = new.tableRef("emp", "PostgreSQL", "postgre.config", "public") +dept = new.tableRef("dept", "HBase", "hbase-site.xml", "default") +q = query.select(function (x) { + res = new.env() + res$ename = x$ename + res }, + query.where(function (x) x$loc == "NEW YORK", + query.join(query.from(emp), query.from(dept), function (x,y) x$deptno == y$deptno))) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/QueryJoinCrossDatabases.out b/com.oracle.truffle.r.test/tests/QueryJoinCrossDatabases.out new file mode 100644 index 0000000000000000000000000000000000000000..cbe7579f1f501521493744679959003df4419b5f --- /dev/null +++ b/com.oracle.truffle.r.test/tests/QueryJoinCrossDatabases.out @@ -0,0 +1,5 @@ + ename +1 CLARK +2 KING +3 MILLER + diff --git a/com.oracle.truffle.r.test/tests/hbase/QueryGroup.R b/com.oracle.truffle.r.test/tests/hbase/QueryGroup.R new file mode 100644 index 0000000000000000000000000000000000000000..af7ff70b113d59d629dff64be81ccaaa1e48089d --- /dev/null +++ b/com.oracle.truffle.r.test/tests/hbase/QueryGroup.R @@ -0,0 +1,10 @@ +emp = new.tableRef("emp", "HBase", "hbase-site.xml", "default") +q = query.group(function (x) c(x$deptno), + query.select(function (x) { + res = new.env() + res$deptno = x$deptno + res$sumSal = sum(x$sal) + res }, + query.from(emp))) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/hbase/QueryGroup.out b/com.oracle.truffle.r.test/tests/hbase/QueryGroup.out new file mode 100644 index 0000000000000000000000000000000000000000..5739114066855bf44b32225bcdd22826843a82cd --- /dev/null +++ b/com.oracle.truffle.r.test/tests/hbase/QueryGroup.out @@ -0,0 +1,5 @@ + sumsal deptno +1 4047 1 +2 13356 3 +3 15810 2 + diff --git a/com.oracle.truffle.r.test/tests/hbase/QuerySimple.R b/com.oracle.truffle.r.test/tests/hbase/QuerySimple.R new file mode 100644 index 0000000000000000000000000000000000000000..2424aee7cdb6604157798340bf30e850f4f9d8bd --- /dev/null +++ b/com.oracle.truffle.r.test/tests/hbase/QuerySimple.R @@ -0,0 +1,8 @@ +emp = new.tableRef("emp", "HBase", "hbase-site.xml", "default") +q = query.select(function (x) { + res = new.env() + res$ename = x$ename + res }, + query.from(emp)) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/hbase/QuerySimple.out b/com.oracle.truffle.r.test/tests/hbase/QuerySimple.out new file mode 100644 index 0000000000000000000000000000000000000000..fede24703d03399465a1ff3bac5db28040aed622 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/hbase/QuerySimple.out @@ -0,0 +1,16 @@ + ename +1 SMITH +2 TURNER +3 ADAMS +4 JAMES +5 FORD +6 MILLER +7 ALLEN +8 WARD +9 JONES +10 MARTIN +11 BLAKE +12 CLARK +13 SCOTT +14 KING + diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunction.R b/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunction.R new file mode 100644 index 0000000000000000000000000000000000000000..86909b7734dee6150f91b1d492093e48d0bf1b36 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunction.R @@ -0,0 +1,14 @@ +dol_to_euro = function (dol) dol * 89.0 / 100.0 + +emp = new.tableRef("emp", "PostgreSQL", "postgre.config", "public") +minsalary = 2500.0 +q = query.select(function (x) { + res = new.env() + res$empno = x$empno + res$ename = x$ename + res$salary = dol_to_euro(x$sal) + res }, + query.where(function (x) x$sal >= minsalary, + query.from(emp))) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunction.out b/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunction.out new file mode 100644 index 0000000000000000000000000000000000000000..e8791d46bbef34fc6421899df046ef917b8db886 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunction.out @@ -0,0 +1,7 @@ + ename empno salary +1 SMITH 1 2225.00 +2 WARD 3 4645.80 +3 JONES 4 3115.00 +4 SCOTT 8 3769.15 +5 ADAMS 11 4450.00 + diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunctionWithDeps.R b/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunctionWithDeps.R new file mode 100644 index 0000000000000000000000000000000000000000..8f2f0297aefff9f701d66e9b7c31a6981cefc46a --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunctionWithDeps.R @@ -0,0 +1,15 @@ +dol_to_euro = function (dol) dol * 89.0 / 100.0 +dol_to_euro2 = dol_to_euro + +emp = new.tableRef("emp", "PostgreSQL", "postgre.config", "public") +minsalary = 2500.0 +q = query.select(function (x) { + res = new.env() + res$empno = x$empno + res$ename = x$ename + res$salary = dol_to_euro2(x$sal) + res }, + query.where(function (x) x$sal >= minsalary, + query.from(emp))) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunctionWithDeps.out b/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunctionWithDeps.out new file mode 100644 index 0000000000000000000000000000000000000000..e8791d46bbef34fc6421899df046ef917b8db886 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunctionWithDeps.out @@ -0,0 +1,7 @@ + ename empno salary +1 SMITH 1 2225.00 +2 WARD 3 4645.80 +3 JONES 4 3115.00 +4 SCOTT 8 3769.15 +5 ADAMS 11 4450.00 + diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryGroup.R b/com.oracle.truffle.r.test/tests/pgsql/QueryGroup.R new file mode 100644 index 0000000000000000000000000000000000000000..403e66eb84b0fcf37faeb16c0bfbbc2cdc0751e9 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryGroup.R @@ -0,0 +1,10 @@ +emp = new.tableRef("emp", "PostgreSQL", "postgre.config", "public") +q = query.group(function (x) c(x$deptno), + query.select(function (x) { + res = new.env() + res$deptno = x$deptno + res$sumSal = sum(x$sal) + res }, + query.from(emp))) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryGroup.out b/com.oracle.truffle.r.test/tests/pgsql/QueryGroup.out new file mode 100644 index 0000000000000000000000000000000000000000..5739114066855bf44b32225bcdd22826843a82cd --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryGroup.out @@ -0,0 +1,5 @@ + sumsal deptno +1 4047 1 +2 13356 3 +3 15810 2 + diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryInline.R b/com.oracle.truffle.r.test/tests/pgsql/QueryInline.R new file mode 100644 index 0000000000000000000000000000000000000000..593c5bd06f535d7842de0518b2d68c4061d65259 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryInline.R @@ -0,0 +1,7 @@ +q = query.select(function (x) { + res = new.env() + res$ename = x$ename + res }, + query.from(new.tableRef("emp", "PostgreSQL", "postgre.config", "public"))) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryInline.out b/com.oracle.truffle.r.test/tests/pgsql/QueryInline.out new file mode 100644 index 0000000000000000000000000000000000000000..356dee918520abf13a9eae9c5862667d60f3f32b --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryInline.out @@ -0,0 +1,16 @@ + ename +1 SMITH +2 ALLEN +3 WARD +4 JONES +5 MARTIN +6 BLAKE +7 CLARK +8 SCOTT +9 KING +10 TURNER +11 ADAMS +12 JAMES +13 FORD +14 MILLER + diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryInlineWithFreeVars.R b/com.oracle.truffle.r.test/tests/pgsql/QueryInlineWithFreeVars.R new file mode 100644 index 0000000000000000000000000000000000000000..f479ee11dad2924d24265b420436a00da3fe2bd5 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryInlineWithFreeVars.R @@ -0,0 +1,11 @@ +tableName = "emp" +dbName = "PostgreSQL" +configFile = "postgre.config" +schemaName = "public" +q = query.select(function (x) { + res = new.env() + res$ename = x$ename + res }, + query.from(new.tableRef("emp", "PostgreSQL", "postgre.config", "public"))) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryInlineWithFreeVars.out b/com.oracle.truffle.r.test/tests/pgsql/QueryInlineWithFreeVars.out new file mode 100644 index 0000000000000000000000000000000000000000..356dee918520abf13a9eae9c5862667d60f3f32b --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryInlineWithFreeVars.out @@ -0,0 +1,16 @@ + ename +1 SMITH +2 ALLEN +3 WARD +4 JONES +5 MARTIN +6 BLAKE +7 CLARK +8 SCOTT +9 KING +10 TURNER +11 ADAMS +12 JAMES +13 FORD +14 MILLER + diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryJoin.R b/com.oracle.truffle.r.test/tests/pgsql/QueryJoin.R new file mode 100644 index 0000000000000000000000000000000000000000..fdc09299ceaf6c6d10e4deb7e178c39139c4bd73 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryJoin.R @@ -0,0 +1,10 @@ +emp = new.tableRef("emp", "PostgreSQL", "postgre.config", "public") +dept = new.tableRef("dept", "PostgreSQL", "postgre.config", "public") +q = query.select(function (x) { + res = new.env() + res$ename = x$ename + res }, + query.where(function (x) x$loc == "NEW YORK", + query.join(query.from(emp), query.from(dept), function (x,y) x$deptno == y$deptno))) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryJoin.out b/com.oracle.truffle.r.test/tests/pgsql/QueryJoin.out new file mode 100644 index 0000000000000000000000000000000000000000..cbe7579f1f501521493744679959003df4419b5f --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryJoin.out @@ -0,0 +1,5 @@ + ename +1 CLARK +2 KING +3 MILLER + diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryJoinCrossDatabases.R b/com.oracle.truffle.r.test/tests/pgsql/QueryJoinCrossDatabases.R new file mode 100644 index 0000000000000000000000000000000000000000..6fe629b7af40051082be0703f64e2307a89072cb --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryJoinCrossDatabases.R @@ -0,0 +1,10 @@ +emp = new.tableRef("emp", "PostgreSQL", "postgre.config", "public") +dept = new.tableRef("dept", "PostgreSQL", "postgre2.config", "public") +q = query.select(function (x) { + res = new.env() + res$ename = x$ename + res }, + query.where(function (x) x$loc == "NEW YORK", + query.join(query.from(emp), query.from(dept), function (x,y) x$deptno == y$deptno))) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryJoinCrossDatabases.out b/com.oracle.truffle.r.test/tests/pgsql/QueryJoinCrossDatabases.out new file mode 100644 index 0000000000000000000000000000000000000000..8952963704068ed8a5ebee42f41e93e8193281db --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryJoinCrossDatabases.out @@ -0,0 +1,8 @@ + ename +1 SMITH +2 WARD +3 JONES +4 MARTIN +5 JAMES +6 FORD + diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryLambda.R b/com.oracle.truffle.r.test/tests/pgsql/QueryLambda.R new file mode 100644 index 0000000000000000000000000000000000000000..85e7be39c434aebd3d94bc0d8b8e6c75ce9cea51 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryLambda.R @@ -0,0 +1,12 @@ +emp = new.tableRef("emp", "PostgreSQL", "postgre.config", "public") +minsalary = 2500.0 +q = query.select(function (x) { + res = new.env() + res$empno = x$empno + res$ename = x$ename + res$salary = (function (dol) dol * 89.0 / 100.0)(x$sal) + res }, + query.where(function (x) x$sal >= minsalary, + query.from(emp))) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryLambda.out b/com.oracle.truffle.r.test/tests/pgsql/QueryLambda.out new file mode 100644 index 0000000000000000000000000000000000000000..e8791d46bbef34fc6421899df046ef917b8db886 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryLambda.out @@ -0,0 +1,7 @@ + ename empno salary +1 SMITH 1 2225.00 +2 WARD 3 4645.80 +3 JONES 4 3115.00 +4 SCOTT 8 3769.15 +5 ADAMS 11 4450.00 + diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryNested.R b/com.oracle.truffle.r.test/tests/pgsql/QueryNested.R new file mode 100644 index 0000000000000000000000000000000000000000..4ddc544bb0cdb9936fa4f27fe534b595f953e28a --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryNested.R @@ -0,0 +1,25 @@ +# Returns the exchange rate between rfrom and rto +getRate = function(rfrom, rto) +{ + change = new.tableRef("change", "PostgreSQL", "postgre.config", "public") + rate = query.force(query.where(function (r) r$cfrom == rfrom && r$cto == rto, + query.from(change))) + if (rfrom == rto) 1.0 else rate$change +} + +# Returns the names of employees earning at least minSalary in the curr +# currency +atLeast = function(minSalary, curr) +{ + emp = new.tableRef("emp", "PostgreSQL", "postgre.config", "public") + query.select(function (e) { r = new.env() + r$name = e$ename + r }, + query.where(function (e) e$sal >= minSalary * getRate("USD", curr), + query.from(emp))) +} + +richUSPeople = atLeast(2000.0, "USD") +richEURPeople = atLeast(2000.0, "EUR") +print(query.force(richUSPeople)) +print(query.force(richEURPeople)) diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryNested.out b/com.oracle.truffle.r.test/tests/pgsql/QueryNested.out new file mode 100644 index 0000000000000000000000000000000000000000..53da7150c82f6978dfcb1dec73b98d72aa03d3cf --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryNested.out @@ -0,0 +1,18 @@ + name +1 SMITH +2 ALLEN +3 WARD +4 JONES +5 SCOTT +6 ADAMS +7 MILLER + name +1 SMITH +2 ALLEN +3 WARD +4 JONES +5 SCOTT +6 ADAMS +7 FORD +8 MILLER + diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryPartial.R b/com.oracle.truffle.r.test/tests/pgsql/QueryPartial.R new file mode 100644 index 0000000000000000000000000000000000000000..869b0f9e2893e13f3322bdd96a0c602a826325e9 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryPartial.R @@ -0,0 +1,13 @@ +movie = new.tableRef("movie", "PostgreSQL", "postgre.config", "public") + +filter = function (collection) + query.where(function (line) line$year < 1990 && line$year > 1985, collection) + +results = query.select(function (movie) { + res = new.env() + res$title = movie$title + res }, + filter( + query.from(movie))) + +print(query.force(results)) diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryPartial.out b/com.oracle.truffle.r.test/tests/pgsql/QueryPartial.out new file mode 100644 index 0000000000000000000000000000000000000000..f4be23850b819e07ea7887f35e4da29fda591f65 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QueryPartial.out @@ -0,0 +1,89 @@ + title +1 The Naked Gun: From the Files of Police Squad! +2 Scrooged +3 Parenthood +4 The Accidental Tourist +5 The Little Mermaid +6 The Untouchables +7 Castle in the Sky +8 Heathers +9 Dangerous Liaisons +10 Good Morning, Vietnam +11 Spaceballs +12 When Harry Met Sally... +13 Big +14 Tin Men +15 The Last Emperor +16 Batman +17 The Princess Bride +18 Crocodile Dundee +19 Working Girl +20 Hoosiers +21 Tango & Cash +22 Bull Durham +23 Throw Momma from the Train +24 Casualties of War +25 9½ Weeks +26 Major League +27 Uncle Buck +28 Tucker: The Man and His Dream +29 Ghostbusters II +30 The War of the Roses +31 At Close Range +32 Platoon +33 Broadcast News +34 Sex, Lies, and Videotape +35 A Fish Called Wanda +36 My Left Foot +37 Fatal Attraction +38 Children of a Lesser God +39 Ironweed +40 Little Shop of Horrors +41 Lean on Me +42 Wall Street +43 Crimes and Misdemeanors +44 Something Wild +45 Blue Velvet +46 Dead Poets Society +47 Do the Right Thing +48 The Last Temptation of Christ +49 Planes, Trains & Automobiles +50 Glory +51 Young Guns +52 Say Anything... +53 Die Hard +54 Hannah and Her Sisters +55 Crimes of the Heart +56 Tequila Sunrise +57 Full Metal Jacket +58 Born on the Fourth of July +59 Raising Arizona +60 Moonstruck +61 Ferris Bueller's Day Off +62 Radio Days +63 Top Gun +64 National Lampoon's Christmas Vacation +65 Lethal Weapon +66 Beetlejuice +67 My Neighbor Totoro +68 Bill & Ted's Excellent Adventure +69 The Accused +70 Predator +71 The Fabulous Baker Boys +72 ¡Three Amigos! +73 The Color of Money +74 The Great Mouse Detective +75 Driving Miss Daisy +76 Less Than Zero +77 The Unbearable Lightness of Being +78 Indiana Jones and the Last Crusade +79 Honey, I Shrunk the Kids +80 The Land Before Time +81 Mississippi Burning +82 Back to the Future Part II +83 The Fly +84 Field of Dreams +85 Rain Man +86 Who Framed Roger Rabbit +87 Another Woman + 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..3ddb0e6a3337befbf1b53902e1e94cd957178dd8 --- /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.0 +q = query.select(function (x) { + res = new.env() + res$empno = x$empno + res$ename = x$ename + res$salary = (function (dol){ + a = dol * 89.0 / 100.0 + while (a > 1000.0) a = a * 89.0 / 100.0 + a + })(x$sal) + res }, + query.where(function (x) x$sal >= minsalary, + query.from(emp))) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/pgsql/QuerySideEffect.out b/com.oracle.truffle.r.test/tests/pgsql/QuerySideEffect.out new file mode 100644 index 0000000000000000000000000000000000000000..ae30189ca424eb38b87f5bc998d4383ccd07a1c2 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QuerySideEffect.out @@ -0,0 +1,7 @@ + ename empno salary +1 SMITH 1 984.1472014255202 +2 WARD 3 908.9094161734163 +3 JONES 4 971.310575818447 +4 SCOTT 8 930.9438795980075 +5 ADAMS 11 978.2054933202209 + diff --git a/com.oracle.truffle.r.test/tests/pgsql/QuerySimple.R b/com.oracle.truffle.r.test/tests/pgsql/QuerySimple.R new file mode 100644 index 0000000000000000000000000000000000000000..832f3de143155ccddd61dc45d8a993fe34e07b8d --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QuerySimple.R @@ -0,0 +1,8 @@ +emp = new.tableRef("emp", "PostgreSQL", "postgre.config", "public") +q = query.select(function (x) { + res = new.env() + res$ename = x$ename + res }, + query.from(emp)) +results = query.force(q) +print(results) diff --git a/com.oracle.truffle.r.test/tests/pgsql/QuerySimple.out b/com.oracle.truffle.r.test/tests/pgsql/QuerySimple.out new file mode 100644 index 0000000000000000000000000000000000000000..356dee918520abf13a9eae9c5862667d60f3f32b --- /dev/null +++ b/com.oracle.truffle.r.test/tests/pgsql/QuerySimple.out @@ -0,0 +1,16 @@ + ename +1 SMITH +2 ALLEN +3 WARD +4 JONES +5 MARTIN +6 BLAKE +7 CLARK +8 SCOTT +9 KING +10 TURNER +11 ADAMS +12 JAMES +13 FORD +14 MILLER + diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH1.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH1.R new file mode 100644 index 0000000000000000000000000000000000000000..8e483ac8afb8ed3b19038ca66b73d6e91c4682b4 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH1.R @@ -0,0 +1,20 @@ +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$l_returnflag, x$l_linestatus), function(x) c(TRUE, TRUE), +group(function(x) c(x$l_returnflag, x$l_linestatus), +select(function(x){ + y = new.env() + y$l_returnflag = x$l_returnflag + y$l_linestatus = x$l_linestatus + y$sum_qty = sum(x$l_quantity) + y$sum_base_price = sum(x$l_extendedprice) + y$sum_disc_price = sum(x$l_extendedprice * (1 - x$l_discount)) + y$sum_charge = sum(x$l_extendedprice * (1 - x$l_discount) * (1 + x$l_tax)) + y$avg_qty = mean(x$l_quantity) + y$avg_price = mean(x$l_extendedprice) + y$avg_disc = mean(x$l_discount) + y$count_order = length() + y}, +where(function(x) x$l_shipdate <= date("1998-12-01") - interval(90, "day"), +from(lineitem))))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH10.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH10.R new file mode 100644 index 0000000000000000000000000000000000000000..79e850acaf2f1676999bb3908cfc78f41cdc3d6b --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH10.R @@ -0,0 +1,30 @@ +customer = new.tableRef("customer", "PostgreSQL", "postgre.config", "tpch") +orders = new.tableRef("orders", "PostgreSQL", "postgre.config", "tpch") +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +nation = new.tableRef("nation", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$revenue), function(x) c(FALSE), +group(function(x) c(x$c_custkey, x$c_name, x$c_acctbal, x$c_phone, x$n_name, x$c_address, x$c_comment), +select(function(x){ + y = new.env() + y$c_custkey = x$c_custkey + y$c_name = x$c_name + y$revenue = sum(x$l_extendedprice * (1 - x$l_discount)) + y$c_acctbal = x$c_acctbal + y$n_name = x$n_name + y$c_address = x$c_address + y$c_phone = x$c_phone + y$c_comment = x$c_comment + y +}, +where(function(x) x$o_orderdate >= date("1993-10-01") + && x$o_orderdate < date("1993-10-01") + interval(3, "month") + && x$l_returnflag == "R", +join(from(nation), +join(from(customer), +join(from(lineitem), + from(orders), + function(x, y) x$l_orderkey == y$o_orderkey), + function(x, y) x$c_custkey == y$o_custkey), + function(x, y) x$n_nationkey == y$c_nationkey))))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH11.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH11.R new file mode 100644 index 0000000000000000000000000000000000000000..eb4750784a7fab549041e44d4fdb008209015ad6 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH11.R @@ -0,0 +1,31 @@ +partsupp = new.tableRef("partsupp", "PostgreSQL", "postgre.config", "tpch") +supplier = new.tableRef("supplier", "PostgreSQL", "postgre.config", "tpch") +nation = new.tableRef("nation", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$value), function(x) c(FALSE), +group(function(x) having( + x$ps_partkey, sum(x$ps_supplycost * x$ps_availqty) > + select(function(x){ + y = new.env() + y$sumps = sum(x$ps_supplycost * x$ps_availqty) * 0.0001 + y + }, + where(function(x) x$n_name == "GERMANY", + join(from(partsupp), + join(from(supplier), + from(nation), + function(x, y) x$s_nationkey == y$n_nationkey), + function(x, y) x$ps_suppkey == y$s_suppkey))) +), +select(function(x){y = new.env() + y$ps_partkey = x$ps_partkey + y$value = sum(x$ps_supplycost * x$ps_availqty) + y +}, +where(function(x) x$n_name == "GERMANY", +join(from(partsupp), +join(from(supplier), + from(nation), + function(x, y) x$s_nationkey == y$n_nationkey), + function(x, y) x$ps_suppkey == y$s_suppkey))))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH12.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH12.R new file mode 100644 index 0000000000000000000000000000000000000000..379f087147b0acddbbcaafd9ef590fe0f117eacd --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH12.R @@ -0,0 +1,20 @@ +orders = new.tableRef("orders", "PostgreSQL", "postgre.config", "tpch") +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$l_shipmode), function(x) c(TRUE), +group(function(x) c(x$l_shipmode), +select(function(x){ + y = new.env() + y$l_shipmode = x$l_shipmode + y$high_line_count = sum(if (x$o_orderpriority == "1-URGENT" || x$o_orderpriority == "2-HIGH") 1 else 0) + y$low_line_count = sum(if (x$o_orderpriority != "1-URGENT" && x$o_orderpriority != "2-HIGH") 1 else 0) + y +}, +where(function(x) (x$l_shipmode == "MAIL" || x$l_shipmode == "SHIP") + && x$l_commitdate < x$l_receiptdate && x$l_shipdate < x$l_commitdate + && x$l_receiptdate >= date("1994-01-01") + && x$l_receiptdate < date("1994-01-01") + interval(1, "year"), +join(from(orders), + from(lineitem), + function(x, y) x$o_orderkey == y$l_orderkey))))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH13.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH13.R new file mode 100644 index 0000000000000000000000000000000000000000..f2142740a0730c2623b98b1a8fd77be7bc2953ab --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH13.R @@ -0,0 +1,21 @@ +customer = new.tableRef("customer", "PostgreSQL", "postgre.config", "tpch") +orders = new.tableRef("orders", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$custdist, x$c_count), function(x) c(FALSE, FALSE), +group(function(x) c(x$c_count), +select(function(x){ + y = new.env() + y$c_count = x$c_count + y$custdist = length() + y +}, +from(group(function(x) c(x$c_custkey), + select(function(x){ + y = new.env() + y$c_custkey = x$c_custkey + y$c_count = length(x$o_orderkey) + y + }, + leftJoin(from(customer), from(orders), + function(x, y) x$c_custkey == y$o_custkey && !(regexpr("%special%requests%", y$o_comment))))))))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH14.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH14.R new file mode 100644 index 0000000000000000000000000000000000000000..0140252c33085035497c8cea2e9f19d7d6e9bb95 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH14.R @@ -0,0 +1,12 @@ +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +part = new.tableRef("part", "PostgreSQL", "postgre.config", "tpch") +q = +select(function(x){ + y = new.env() + y$promo_revenue = 100.00 * sum(if (regexpr("PROMO%", x$p_type)) x$l_extendedprice * (1 - x$l_discount) else 0) / sum(x$l_extendedprice * (1 - x$l_discount)) + y +}, +where(function(x) x$l_shipdate >= date("1995-09-01") + && x$l_shipdate < date("1995-09-01") + interval(1, "month"), +join(from(lineitem), from(part), function(x, y) x$l_partkey == y$p_partkey))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH15-se.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH15-se.R new file mode 100644 index 0000000000000000000000000000000000000000..ed31330255ad75c9adc9ac8a1ca0e789b113c914 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH15-se.R @@ -0,0 +1,27 @@ +max_rev = function() { + while (y == null) y = new.env() + select(function(x){ + y = new.env() + y$totalrevenue = max(x$total_revenue) + y + }, + from(revenue)) +} + +supplier = new.tableRef("supplier", "PostgreSQL", "postgre.config", "tpch") +revenue = new.tableRef("revenue", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$s_suppkey), function(x) c(TRUE), +select(function(x){ + y = new.env() + y$s_suppkey = x$s_suppkey + y$s_name = x$s_name + y$s_address = x$s_address + y$s_phone = x$s_phone + y$total_revenue = x$total_revenue + y +}, +where(function(x){x$total_revenue == max_rev()}, +join(from(supplier), +from(revenue), function(x, y) x$s_suppkey == y$supplier_no)))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH15-udf.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH15-udf.R new file mode 100644 index 0000000000000000000000000000000000000000..56a0ee187b5163993d271aedbe3a3dbe2e63ef0b --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH15-udf.R @@ -0,0 +1,26 @@ +max_rev = function() { + select(function(x){ + y = new.env() + y$totalrevenue = max(x$total_revenue) + y + }, + from(revenue)) +} + +supplier = new.tableRef("supplier", "PostgreSQL", "postgre.config", "tpch") +revenue = new.tableRef("revenue", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$s_suppkey), function(x) c(TRUE), +select(function(x){ + y = new.env() + y$s_suppkey = x$s_suppkey + y$s_name = x$s_name + y$s_address = x$s_address + y$s_phone = x$s_phone + y$total_revenue = x$total_revenue + y +}, +where(function(x){x$total_revenue == max_rev()}, +join(from(supplier), +from(revenue), function(x, y) x$s_suppkey == y$supplier_no)))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH15.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH15.R new file mode 100644 index 0000000000000000000000000000000000000000..ea4cd6869fd8e0add8e8ace85c56d952f0eaebfc --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH15.R @@ -0,0 +1,24 @@ +supplier = new.tableRef("supplier", "PostgreSQL", "postgre.config", "tpch") +revenue = new.tableRef("revenue", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$s_suppkey), function(x) c(TRUE), +select(function(x){ + y = new.env() + y$s_suppkey = x$s_suppkey + y$s_name = x$s_name + y$s_address = x$s_address + y$s_phone = x$s_phone + y$total_revenue = x$total_revenue + y +}, +where(function(x){x$total_revenue == + select(function(x){ + y = new.env() + y$totalrevenue = max(x$total_revenue) + y + }, + from(revenue)) +}, +join(from(supplier), +from(revenue), function(x, y) x$s_suppkey == y$supplier_no)))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH16.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH16.R new file mode 100644 index 0000000000000000000000000000000000000000..35d78e4d6e34abb7e315b6a49c378c97510dd44e --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH16.R @@ -0,0 +1,28 @@ +supplier = new.tableRef("supplier", "PostgreSQL", "postgre.config", "tpch") +partsupp = new.tableRef("partsupp", "PostgreSQL", "postgre.config", "tpch") +part = new.tableRef("part", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$supplier_cnt, x$p_brand, x$p_type, x$p_size), function(x) c(FALSE, TRUE, TRUE, TRUE), +group(function(x) c(x$p_brand, x$p_type, x$p_size), +select(function(x){ + y = new.env() + y$p_brand = x$p_brand + y$p_type = x$p_type + y$p_size = x$p_size + y$supplier_cnt = length(x$ps_suppkey) + y +}, +where(function(x) x$p_brand != 'Brand#45' && !(regexpr('MEDIUM POLISHED%', x$p_type)) + && match(x$p_size, c(49, 14, 23, 45, 19, 3, 36, 9)) + && !match(x$ps_suppkey, query.force( + select(function(y){ + z = new.env() + z$s_suppkey = y$s_suppkey + z + }, + where(function(y) regexpr("%Customer%Complaints%", y$s_comment), + from(supplier))))), +join(from(partsupp), + from(part), + function(x, y) x$ps_partkey == y$p_partkey))))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH17.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH17.R new file mode 100644 index 0000000000000000000000000000000000000000..07a93344764d91f6065592edf3c27a4a27f1bd0c --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH17.R @@ -0,0 +1,22 @@ +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +part = new.tableRef("part", "PostgreSQL", "postgre.config", "tpch") +q = +select(function(x){ + y = new.env() + y$avg_yearly = sum(x$l_extendedprice) / 7.0 + y +}, +where(function(x) x$p_brand == 'Brand#23' && x$p_container == 'MED BOX' + && x$l_quantity < query.force( + select(function(y){ + z = new.env() + z$sum_qty = 0.2 * mean(y$l_quantity) + z + }, + where(function(y) y$l_partkey == x$p_partkey, + from(lineitem))) + ), +join(from(lineitem), + from(part), + function(x, y) x$l_partkey == y$p_partkey))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH18.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH18.R new file mode 100644 index 0000000000000000000000000000000000000000..5724bd455bfe789cf50beffddf2fd630aea8138a --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH18.R @@ -0,0 +1,31 @@ +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +customer = new.tableRef("customer", "PostgreSQL", "postgre.config", "tpch") +orders = new.tableRef("orders", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$o_totalprice, x$o_orderdate), function(x) c(FALSE, TRUE), +group(function(x) c(x$c_name, x$c_custkey, x$o_orderkey, x$o_orderdate, x$o_totalprice), +select(function(x){ + y = new.env() + y$c_name = x$c_name + y$c_custkey = x$c_custkey + y$o_orderkey = x$o_orderkey + y$o_orderdate = x$o_orderdate + y$o_totalprice = x$o_totalprice + y$sum_qty = sum(x$l_quantity) + y +}, +where(function(x) match(x$o_orderkey, query.force( + group(function(y) having(y$l_orderkey, sum(y$l_quantity) > 300), + select(function(y){ + z = new.env() + z$l_orderkey = y$l_orderkey + z + }, + from(lineitem))))) +, +join(from(customer), +join(from(orders), + from(lineitem), + function(x, y) x$o_orderkey == y$l_orderkey), + function(x, y) x$c_custkey == y$o_custkey))))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH19.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH19.R new file mode 100644 index 0000000000000000000000000000000000000000..ead35151062a362a62ac231c379652a427c99dbf --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH19.R @@ -0,0 +1,23 @@ +part = new.tableRef("part", "PostgreSQL", "postgre.config", "tpch") +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +q = +select(function(x){ + y = new.env() + y$revenue = sum(x$l_extendedprice * (1 - x$l_discount)) + y +}, +where(function(x) + (x$p_brand == 'Brand#12' && match(x$p_container, c('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG')) + && x$l_quantity >= 1 && x$l_quantity <= 1 + 10 && x$p_size >= 1 && x$p_size <= 5 + && match(x$l_shipmode, c('AIR', 'AIR REG')) && x$l_shipinstruct == 'DELIVER IN PERSON') + || (x$p_brand == 'Brand#23' && match(x$p_container, c('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK')) + && x$l_quantity >= 10 && x$l_quantity <= 10 + 10 && x$p_size >= 1 && x$p_size <= 10 + && match(x$l_shipmode, c('AIR', 'AIR REG')) && x$l_shipinstruct == 'DELIVER IN PERSON') + || (x$p_brand == 'Brand#34' && match(x$p_container, c('LG CASE', 'LG BOX', 'LG PACK', 'LG PKG')) + && x$l_quantity >= 20 && x$l_quantity <= 20 + 10 && x$p_size >= 1 && x$p_size <= 15 + && match(x$l_shipmode, c('AIR', 'AIR REG')) && x$l_shipinstruct == 'DELIVER IN PERSON') +, +join(from(part), + from(lineitem), + function(x, y) x$p_partkey == y$l_partkey))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH2.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH2.R new file mode 100644 index 0000000000000000000000000000000000000000..1914b57df3d858e7ef48e4fe41203064f2cb1d31 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH2.R @@ -0,0 +1,44 @@ +part = new.tableRef("part", "PostgreSQL", "postgre.config", "tpch") +partsupp = new.tableRef("partsupp", "PostgreSQL", "postgre.config", "tpch") +supplier = new.tableRef("supplier", "PostgreSQL", "postgre.config", "tpch") +nation = new.tableRef("nation", "PostgreSQL", "postgre.config", "tpch") +region = new.tableRef("region", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$s_acctbal, x$n_name, x$s_name, x$p_partkey), function (x) c(FALSE, TRUE, TRUE, TRUE), +select(function(x){ + y = new.env() + y$s_acctbal = x$s_acctbal + y$s_name = x$s_name + y$n_name = x$n_name + y$p_partkey = x$p_partkey + y$p_mfgr = x$p_mfgr + y$s_address = x$s_address + y$s_phone = x$s_phone + y$s_comment = x$s_comment + y +}, +where(function(x) x$p_size == 15 && regexpr("%BRASS", x$p_type) && x$r_name == "EUROPE" + && x$ps_supplycost == select(function(x){ + y = new.env() + y$msc = min(x$ps_supplycost) + y + }, + where(function(x) x$r_name == "EUROPE", + join(from(partsupp), + join(from(supplier), + join(from(nation), + from(region), + function(y, z) y$n_regionkey == z$r_regionkey), + function(y, z) y$s_nationkey == z$n_nationkey), + function(y, z) y$ps_partkey == x$p_partkey + && y$ps_suppkey == z$s_suppkey))), + join(from(part), + join(from(partsupp), + join(from(supplier), + join(from(nation), + from(region), + function(x, y) x$n_regionkey == y$r_regionkey), + function(x, y) x$s_nationkey == y$n_nationkey), + function(x, y) x$ps_suppkey == y$s_suppkey), + function(x, y) x$p_partkey == y$ps_partkey)))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH20.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH20.R new file mode 100644 index 0000000000000000000000000000000000000000..505ac5a29a748e50dd3ed8bfef957c876ea44660 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH20.R @@ -0,0 +1,51 @@ +supplier = new.tableRef("supplier", "PostgreSQL", "postgre.config", "tpch") +nation = new.tableRef("nation", "PostgreSQL", "postgre.config", "tpch") +part = new.tableRef("part", "PostgreSQL", "postgre.config", "tpch") +partsupp = new.tableRef("partsupp", "PostgreSQL", "postgre.config", "tpch") +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$s_name), function(x) c(TRUE), +select(function(x){ + y = new.env() + y$s_name = x$s_name + y$s_address = x$s_address + y +}, +where(function(x) x$n_name == 'CANADA' + && match(x$s_suppkey, query.force( + select(function(y){ + z = new.env() + z$ps_suppkey = y$ps_suppkey + z + }, + where(function(y) match(y$ps_partkey, query.force( + select(function(z){ + a = new.env() + a$p_partkey = z$p_partkey + a + }, + where(function(z) regexpr("forest%", z$p_name) + , + from(part))) + )) + && y$ps_availqty > query.force( + select(function(z){ + a = new.env() + a$sum_qty = 0.5 * sum(z$l_quantity) + a + }, + where(function(z) z$l_partkey == y$ps_partkey + && z$l_suppkey == y$ps_suppkey + && z$l_shipdate >= date("1994-01-01") + && z$l_shipdate < date("1994-01-01") + interval(1, "year") + , + from(lineitem))) + ) + , + from(partsupp))) + )) +, +join(from(supplier), + from(nation), + function(x, y) x$s_nationkey == y$n_nationkey)))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH22.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH22.R new file mode 100644 index 0000000000000000000000000000000000000000..f00c9d86edfe1465539a4fdab5990e9398522166 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH22.R @@ -0,0 +1,42 @@ +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +customer = new.tableRef("customer", "PostgreSQL", "postgre.config", "tpch") +orders = new.tableRef("orders", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$cntrycode), function(x) c(TRUE), +group(function(x) c(x$cntrycode), +select(function(x){ + y = new.env() + y$cntrycode = x$cntrycode + y$numcust = length() + y$totacctbal = sum(x$c_acctbal) + y +}, +from( + select(function(x){ + y = new.env() + y$cntrycode = substr(x$c_phone, 1, 2) + y$c_acctbal = x$c_acctbal + y + }, + where(function(x) match(substr(x$c_phone, 1, 2), c('13', '31', '23', '29', '30', '18', '17')) + && x$c_acctbal > query.force( + select(function(y){ + z = new.env() + z$avg_bal = mean(y$c_acctbal) + z + }, + where(function(y) y$c_acctbal > 0.00 + && match(substr(y$c_phone, 1, 2), c('13', '31', '23', '29', '30', '18', '17')) + , + from(customer)))) + && query.force( + select(function(y){ + z = new.env() + z$count_orders = length() + z + }, + where(function(y) y$o_custkey > x$c_custkey, + from(orders)))) == 0, + from(customer))) +)))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH3.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH3.R new file mode 100644 index 0000000000000000000000000000000000000000..630408575814eb7d840c0f9478ea4c883b8a0451 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH3.R @@ -0,0 +1,21 @@ +customer = new.tableRef("customer", "PostgreSQL", "postgre.config", "tpch") +orders = new.tableRef("orders", "PostgreSQL", "postgre.config", "tpch") +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$revenue, x$o_orderdate), function(x) c(FALSE, TRUE), +group(function(x) c(x$l_orderkey, x$o_orderdate, x$o_shippriority), +select(function(x){y = new.env() + y$l_orderkey = x$l_orderkey + y$revenue = sum(x$l_extendedprice * (1 - x$l_discount)) + y$o_orderdate = x$o_orderdate + y$o_shippriority = x$o_shippriority + y +}, +where(function(x) x$c_mktsegment == "BUILDING" + && x$o_orderdate < date("1995-03-15") && x$l_shipdate > date("1995-03-15"), +join(from(customer), +join(from(orders), +from(lineitem), +function(x, y) x$o_orderkey == y$l_orderkey), +function(x, y) x$c_custkey == y$o_custkey))))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH4.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH4.R new file mode 100644 index 0000000000000000000000000000000000000000..8acb494b281fbd742d0b3c7ae717d000daaaac95 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH4.R @@ -0,0 +1,26 @@ +customer = new.tableRef("customer", "PostgreSQL", "postgre.config", "tpch") +orders = new.tableRef("orders", "PostgreSQL", "postgre.config", "tpch") +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$o_orderpriority), function(x) c(TRUE), +group(function(x) c(x$o_orderpriority), +select(function(x){ + y = new.env() + y$o_orderpriority = x$o_orderpriority + y$order_count = length() + y +}, +where(function(x) x$o_orderdate >= date("1993-07-01") + && x$o_orderdate < date("1993-07-01") + interval(3, "month") + && query.force( + select(function(x){ + y = new.env() + y$count = length() + y + }, + where(function(y) y$l_orderkey == x$o_orderkey + && y$l_commitdate < y$l_receiptdate, + from(lineitem))) + ) > 0, +from(orders))))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH5.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH5.R new file mode 100644 index 0000000000000000000000000000000000000000..e34f5c8ff1d43445cba5345e646292acc367c9f1 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH5.R @@ -0,0 +1,29 @@ +customer = new.tableRef("customer", "PostgreSQL", "postgre.config", "tpch") +orders = new.tableRef("orders", "PostgreSQL", "postgre.config", "tpch") +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +supplier = new.tableRef("supplier", "PostgreSQL", "postgre.config", "tpch") +nation = new.tableRef("nation", "PostgreSQL", "postgre.config", "tpch") +region = new.tableRef("region", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$revenue), function(x) c(FALSE), +group(function(x) c(x$n_name), +select(function(x){ + y = new.env() + y$n_name = x$n_name + y$revenue = sum(x$l_extendedprice * (1 - x$l_discount)) + y +}, +where(function(x) x$r_name == "ASIA" && x$o_orderdate >= date("1994-01-01") + && x$o_orderdate < date("1994-01-01") + interval(1, "year"), +join(from(customer), +join(from(orders), +join(from(lineitem), +join(from(supplier), +join(from(nation), + from(region), + function(x, y) x$n_regionkey == y$r_regionkey), + function(x, y) x$s_nationkey == y$n_nationkey), + function(x, y) x$l_suppkey == y$s_suppkey), + function(x, y) x$o_orderkey == y$l_orderkey), + function(x, y) x$c_custkey == y$o_custkey && x$c_nationkey == y$s_nationkey))))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH6.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH6.R new file mode 100644 index 0000000000000000000000000000000000000000..9fe1b33ceca6633df66e791b89e6e42653cf1af7 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH6.R @@ -0,0 +1,11 @@ +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +q = +select(function(x){ + y = new.env() + y$revenue = sum(x$l_extendedprice * x$l_discount) + y +}, +where(function(x) x$l_shipdate >= date("1994-01-01") && x$l_shipdate < date("1994-01-01") + interval(1, "year") + && x$l_discount >= 0.06 - 0.01 && x$l_discount <= 0.06 + 0.01 && x$l_quantity < 24, +from(lineitem))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH7.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH7.R new file mode 100644 index 0000000000000000000000000000000000000000..4db3d200ab36720b55ac7c16f4abc5aee9132f8a --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH7.R @@ -0,0 +1,29 @@ +customer = new.tableRef("customer", "PostgreSQL", "postgre.config", "tpch") +orders = new.tableRef("orders", "PostgreSQL", "postgre.config", "tpch") +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +supplier = new.tableRef("supplier", "PostgreSQL", "postgre.config", "tpch") +nation = new.tableRef("nation", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$supp_nation, x$cust_nation, x$l_year), function(x) c(TRUE, TRUE, TRUE), +group(function(x) c(x$supp_nation, x$cust_nation, x$l_year), +select(function(x){ + y = new.env() + y$supp_nation = x$n_name + y$cust_nation = x$n_name + y$l_year = format(x$l_shipdate, "%Y") + y$volume = x$l_extendedprice * (1 - x$l_discount) + y +}, +join(from(nation), +join(from(nation), +join(from(customer), +join(from(orders), +join(from(supplier), + from(lineitem), + function(x, y)x$s_suppkey == y$l_suppkey), + function(x, y)x$o_orderkey == y$l_orderkey), + function(x, y)x$c_custkey == y$o_custkey), + function(x, y)x$n_nationkey == y$s_nationkey), + function(x, y)x$n_nationkey == y$c_nationkey && ((x$n_name == "FRANCE" && y$n_name == "GERMANY") + || (x$n_name == "GERMANY" && y$n_name == "FRANCE")))))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH8.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH8.R new file mode 100644 index 0000000000000000000000000000000000000000..af28bf1a2629bb4ce211f92762e8106fd2ed0019 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH8.R @@ -0,0 +1,41 @@ +customer = new.tableRef("customer", "PostgreSQL", "postgre.config", "tpch") +orders = new.tableRef("orders", "PostgreSQL", "postgre.config", "tpch") +nation = new.tableRef("nation", "PostgreSQL", "postgre.config", "tpch") +region = new.tableRef("region", "PostgreSQL", "postgre.config", "tpch") +supplier = new.tableRef("supplier", "PostgreSQL", "postgre.config", "tpch") +part = new.tableRef("part", "PostgreSQL", "postgre.config", "tpch") +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$o_year), function(x) c(TRUE), +group(function(x) c(x$o_year), +select(function(x){ + y = new.env() + y$o_year = x$o_year + y$mkt_share = sum(if (x$nation == "BRAZIL") x$volume else 0) / sum(x$volume) + y +}, +from(select(function(x){ + y = new.env() + y$o_year = format(x$o_orderdate, "%Y") + y$volume = x$l_extendedprice * (1 - x$l_discount) + y$nation = x$n_name + y + }, + where(function(x) x$r_name == "AMERICA" && x$p_type == "ECONOMY ANODIZED STEEL" + && x$o_orderdate >= date("1995-01-01") && x$o_orderdate <= date("1996-12-31"), + join(from(nation), + join(from(region), + join(from(nation), + join(from(customer), + join(from(orders), + join(from(supplier), + join(from(part), + from(lineitem), + function(x, y) x$p_partkey == y$l_partkey), + function(x, y) x$s_suppkey == y$l_suppkey), + function(x, y) x$o_orderkey == y$l_orderkey), + function(x, y) x$c_custkey == y$o_custkey), + function(x, y) x$n_nationkey == y$c_nationkey), + function(x, y) x$r_regionkey == y$n_regionkey), + function(x, y) x$n_nationkey == y$s_nationkey))))))) +print(query.force(q)) diff --git a/com.oracle.truffle.r.test/tests/tpch/QueryTPCH9.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH9.R new file mode 100644 index 0000000000000000000000000000000000000000..027104f14e3600e1e0a4a8aa2bb2740565e1b3e9 --- /dev/null +++ b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH9.R @@ -0,0 +1,35 @@ +part = new.tableRef("part", "PostgreSQL", "postgre.config", "tpch") +supplier = new.tableRef("supplier", "PostgreSQL", "postgre.config", "tpch") +lineitem = new.tableRef("lineitem", "PostgreSQL", "postgre.config", "tpch") +partsupp = new.tableRef("partsupp", "PostgreSQL", "postgre.config", "tpch") +orders = new.tableRef("orders", "PostgreSQL", "postgre.config", "tpch") +nation = new.tableRef("nation", "PostgreSQL", "postgre.config", "tpch") +q = +order(function(x) c(x$nation, x$o_year), function(x) c(TRUE, FALSE), +group(function(x) c(x$nation, x$o_year), +select(function(x){ + y = new.env() + y$nation = x$nation + y$o_year = x$o_year + y$sum_profit = sum(x$amount) +y}, +from(select(function(x){ + y = new.env() + y$nation = x$n_name + y$o_year = format(x$o_orderdate, "%Y") + y$amount = x$l_extendedprice * (1 - x$l_discount) - x$ps_supplycost * x$l_quantity + y + }, + where(function(x) regexpr("%green%", x$p_name), + join(from(partsupp), + join(from(orders), + join(from(part), + join(from(lineitem), + join(from(supplier), + from(nation), + function(x, y) x$s_nationkey == y$n_nationkey), + function(x, y) x$l_suppkey == y$s_suppkey), + function(x, y) x$p_partkey == y$l_partkey), + function(x, y) x$o_orderkey == y$l_orderkey), + function(x, y) x$ps_suppkey == y$l_suppkey && x$ps_partkey == y$l_partkey))))))) +print(query.force(q)) diff --git a/mx.fastr/suite.py b/mx.fastr/suite.py index 154838f37e9a3a80639bf5b8f328a617909dc450..4a898db5a388e2dd373b2dd84168c0d92a435a06 100644 --- a/mx.fastr/suite.py +++ b/mx.fastr/suite.py @@ -80,6 +80,26 @@ suite = { "sha1" : "0baa82bff19059401e90e1b90020beb9c96305d7", }, + "JDK_TOOLS" : { + "path" : "${JAVA_HOME}/lib/tools.jar", + "sha1" : "NOCHECK", + }, + + "QIR" : { + "path" : "../qir/qir.jar", + "sha1" : "NOCHECK", + }, + + "PGSQL" : { + "path" : "../lib/postgresql.jar", + "sha1" : "NOCHECK", + }, + + "OJDBC" : { + "path" : "../lib/ojdbc.jar", + "sha1" : "NOCHECK", + }, + "ANTLR-C-3.5" : { "path" : "libdownloads/antlr-complete-3.5.1.jar", "urls" : ["http://central.maven.org/maven2/org/antlr/antlr-complete/3.5.1/antlr-complete-3.5.1.jar"], @@ -123,6 +143,7 @@ suite = { "dependencies" : [ "com.oracle.truffle.r.runtime", "truffle:TRUFFLE_DEBUG", + "QIR" ], "checkstyle" : "com.oracle.truffle.r.runtime", "javaCompliance" : "1.8", @@ -137,6 +158,7 @@ suite = { "sourceDirs" : ["src"], "dependencies" : [ "com.oracle.truffle.r.library", + "QIR" ], "checkstyle" : "com.oracle.truffle.r.runtime", "javaCompliance" : "1.8", @@ -206,6 +228,9 @@ suite = { "com.oracle.truffle.r.parser", "truffle:JLINE", "truffle:TRUFFLE_DEBUG", + "QIR", + "PGSQL", + "OJDBC", "truffle:TRUFFLE_NFI", ], "generatedDependencies" : [ @@ -228,6 +253,7 @@ suite = { "truffle:TRUFFLE_API", "truffle:TRUFFLE_DEBUG", "XZ-1.5", + "QIR" ], "checkstyle" : "com.oracle.truffle.r.runtime", "javaCompliance" : "1.8", diff --git a/oracle.config b/oracle.config new file mode 100644 index 0000000000000000000000000000000000000000..676cc848c308c0a9303477005ca673d05b3017a8 --- /dev/null +++ b/oracle.config @@ -0,0 +1,5 @@ +host = myoracle.com +sid = myview +port = 7658 +user = julilope +passwd = Pa$$w0rd diff --git a/postgre.config b/postgre.config new file mode 100644 index 0000000000000000000000000000000000000000..39dd278151eb10c99d66e7b091e5d6c342b355b4 --- /dev/null +++ b/postgre.config @@ -0,0 +1,5 @@ +host = localhost +sid = postgres +port = 5432 +user = julien +passwd = Pa$$w0rd diff --git a/postgre2.config b/postgre2.config new file mode 100644 index 0000000000000000000000000000000000000000..8ef8ed55fbf64fc1ac673aa5f1ce3e526d6fb55f --- /dev/null +++ b/postgre2.config @@ -0,0 +1,5 @@ +host = localhost +sid = other +port = 5432 +user = julien +passwd = Pa$$w0rd