From 9f334ff70fbdfa757e04c696d7db7ce9cb1da165 Mon Sep 17 00:00:00 2001
From: Julien Lopez <julien.lopez@lri.fr>
Date: Tue, 28 Feb 2017 23:14:15 +0100
Subject: [PATCH] Add query operators and TPC-H tests

---
 .../r/nodes/builtin/base/infix/Subset.java    | 19 +++++++
 .../builtin/query/RForceQueryBuiltin.java     |  4 ++
 .../r/nodes/builtin/query/RTableBuiltin.java  |  4 ++
 .../oracle/truffle/r/nodes/RASTBuilder.java   | 28 +++++++++-
 .../r/nodes/qirinterface/QIRInterface.java    | 47 +++++++++++++----
 .../qirinterface/QIRTranslateVisitor.java     | 24 +++++++--
 .../src/com/oracle/truffle/r/parser/R.g       | 10 +++-
 .../truffle/r/runtime/nodes/RCodeBuilder.java | 22 +++++++-
 .../com/oracle/truffle/r/test/RTestSuite.java | 26 +++++-----
 .../tests/hbase/QueryGroup.R                  |  2 +-
 .../tests/pgsql/QueryCallFunction.out         | 12 ++---
 .../tests/pgsql/QueryCallFunctionWithDeps.out | 12 ++---
 .../tests/pgsql/QueryGroup.R                  |  2 +-
 .../tests/pgsql/QueryLambda.out               | 12 ++---
 .../tests/tpch/QueryTPCH1.R                   | 20 ++++++++
 .../tests/tpch/QueryTPCH10.R                  | 30 +++++++++++
 .../tests/tpch/QueryTPCH11.R                  | 31 +++++++++++
 .../tests/tpch/QueryTPCH12.R                  | 20 ++++++++
 .../tests/tpch/QueryTPCH13.R                  | 21 ++++++++
 .../tests/tpch/QueryTPCH14.R                  | 12 +++++
 .../tests/tpch/QueryTPCH15-se.R               | 27 ++++++++++
 .../tests/tpch/QueryTPCH15-udf.R              | 26 ++++++++++
 .../tests/tpch/QueryTPCH15.R                  | 24 +++++++++
 .../tests/tpch/QueryTPCH16.R                  | 28 ++++++++++
 .../tests/tpch/QueryTPCH17.R                  | 22 ++++++++
 .../tests/tpch/QueryTPCH18.R                  | 31 +++++++++++
 .../tests/tpch/QueryTPCH19.R                  | 23 +++++++++
 .../tests/tpch/QueryTPCH2.R                   | 44 ++++++++++++++++
 .../tests/tpch/QueryTPCH20.R                  | 51 +++++++++++++++++++
 .../tests/tpch/QueryTPCH22.R                  | 42 +++++++++++++++
 .../tests/tpch/QueryTPCH3.R                   | 21 ++++++++
 .../tests/tpch/QueryTPCH4.R                   | 26 ++++++++++
 .../tests/tpch/QueryTPCH5.R                   | 29 +++++++++++
 .../tests/tpch/QueryTPCH6.R                   | 11 ++++
 .../tests/tpch/QueryTPCH7.R                   | 29 +++++++++++
 .../tests/tpch/QueryTPCH8.R                   | 41 +++++++++++++++
 .../tests/tpch/QueryTPCH9.R                   | 35 +++++++++++++
 mx.fastr/suite.py                             | 16 +++++-
 oracle.config                                 |  5 ++
 postgre.config                                |  5 ++
 postgre2.config                               |  5 ++
 41 files changed, 846 insertions(+), 53 deletions(-)
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH1.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH10.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH11.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH12.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH13.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH14.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH15-se.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH15-udf.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH15.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH16.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH17.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH18.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH19.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH2.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH20.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH22.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH3.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH4.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH5.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH6.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH7.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH8.R
 create mode 100644 com.oracle.truffle.r.test/tests/tpch/QueryTPCH9.R
 create mode 100644 oracle.config
 create mode 100644 postgre.config
 create mode 100644 postgre2.config

diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subset.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subset.java
index 82199ccb54..01c2d77264 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subset.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/Subset.java
@@ -40,9 +40,11 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNames
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.nodes.builtin.base.infix.SpecialsUtils.ConvertIndex;
 import com.oracle.truffle.r.nodes.builtin.base.infix.SpecialsUtils.ProfiledValue;
+import com.oracle.truffle.r.nodes.qirinterface.QIRTranslateVisitor;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 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.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RList;
@@ -50,8 +52,13 @@ import com.oracle.truffle.r.runtime.data.RLogical;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 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.QIRNode;
+import qir.ast.operator.QIRFilter;
+import qir.ast.operator.QIRProject;
+
 /**
  * Subset special only handles single element integer/double index. In the case of list, we need to
  * create the actual list otherwise we just return the primitive type.
@@ -121,6 +128,18 @@ public abstract class Subset extends RBuiltinNode {
     }
 
     public static RNode special(ArgumentsSignature signature, RNode[] args, boolean inReplacement) {
+
+        if (args[0].isRSyntaxNode() && args[0].asRSyntaxNode() instanceof REnvironment &&
+                        ((REnvironment) args[0].asRSyntaxNode()).get("queryId") != null) {
+            final Object queryId = ((REnvironment) args[0].asRSyntaxNode()).get("queryId");
+            if (queryId != null) {
+                final QIRNode filter = args[1].asRSyntaxNode().accept(QIRTranslateVisitor.instance);
+                final QIRNode format = args[2].asRSyntaxNode().accept(QIRTranslateVisitor.instance);
+                RContext.queries.set((int) queryId, new QIRProject(null, format, new QIRFilter(null,
+                                filter, RContext.queries.get((int) queryId))));
+                return args[0];
+            }
+        }
         if (signature.getNonNullCount() == 0 && (args.length == 2 || args.length == 3)) {
             ProfiledValue profiledVector = profile(args[0]);
             ConvertIndex index = convertIndex(args[1]);
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
index ccb4167d01..d2e8f77d75 100644
--- 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
@@ -47,6 +47,10 @@ import com.oracle.truffle.r.runtime.env.REnvironment;
  */
 @RBuiltin(name = "query.force", visibility = OFF, kind = PRIMITIVE, parameterNames = {"query"}, behavior = COMPLEX)
 public abstract class RForceQueryBuiltin extends RBuiltinNode {
+    static {
+        Casts.noCasts(RForceQueryBuiltin.class);
+    }
+
     @TruffleBoundary
     @Specialization
     public static final RList force(final REnvironment rQuery) {
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
index 8800644521..bce058f723 100644
--- 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
@@ -36,6 +36,10 @@ 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 {
+    static {
+        Casts.noCasts(RTableBuiltin.class);
+    }
+
     @TruffleBoundary
     @Specialization
     public static final REnvironment table(final String tableName, final String dbName, final String configFile, final String schemaName) {
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 ef378d8e00..dd1255b686 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
@@ -52,7 +52,11 @@ 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;
@@ -174,8 +178,28 @@ public final class RASTBuilder implements RCodeBuilder<RSyntaxNode> {
     }
 
     @Override
-    public final RSyntaxNode groupby(final SourceSection source, final RSyntaxNode filter, final RSyntaxNode child) {
-        return new RGroupNode(source, filter.asRNode(), child.asRNode());
+    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) {
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
index 66b3507413..193698bb14 100644
--- 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
@@ -111,10 +111,14 @@ public final class QIRInterface {
                 final String varName = fv.id;
                 Frame frame = argFrame;
                 FrameSlot varSlot = frame.getFrameDescriptor().findFrameSlot(varName);
-                for (; varSlot == null && frame.getArguments()[4] instanceof Frame; frame = (Frame) frame.getArguments()[4])
+                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()),
-                                RToQIRType(fv.sourceSection, varSlot != null ? frame.getValue(varSlot) : RContext.lookupBuiltin(varName)));
+                                varName.equals("interval") ? new QIRBuiltin(dummy, "interval") : varName.equals("having") ? new QIRBuiltin(dummy, "having") // TODO:
+                                                                                                                                                            // Remove
+                                                                                                                                                            // this
+                                                                                                                                                            // hack
+                                                : RToQIRType(fv.sourceSection, varSlot != null ? frame.getValue(varSlot) : RContext.lookupBuiltin(varName)));
             }
         return query;
     }
@@ -207,8 +211,13 @@ public final class QIRInterface {
             return new QIRBigNumber(src, (BigInteger) value);
         if (value instanceof Long)
             return new QIRNumber(src, (Long) value);
-        if (value instanceof Double)
+        if (value instanceof Byte)
+            return new QIRNumber(src, (Byte) value);
+        if (value instanceof Double) {
+            if ((double) value == Math.floor((double) value))
+                return new QIRNumber(src, ((Double) value).longValue());
             return new QIRDouble(src, (Double) value);
+        }
         if (value instanceof Boolean)
             return QIRBoolean.create((Boolean) value);
         if (value instanceof String)
@@ -220,7 +229,6 @@ public final class QIRInterface {
                 final int qid = ((Long) queryId).intValue();
                 return normalize(RContext.queries.get(qid), RContext.envs.get(qid));
             }
-
             final String tableName = (String) env.get("tableName");
             final String schemaName = (String) env.get("schemaName");
             final String dbName = (String) env.get("dbName");
@@ -247,13 +255,6 @@ public final class QIRInterface {
                     final QIRVariable x = new QIRVariable(null, "x", null);
                     return new QIRLambda(src, "identity", x, x, new FrameDescriptor());
                 }
-                case "c": {
-                    // TODO: This works only for lists with one element
-                    final QIRVariable x = new QIRVariable(null, "x", null);
-                    return new QIRLambda(src, "lcons", x, new QIRLcons(null, x, QIRLnil.instance), new FrameDescriptor());
-                }
-                case "sum":
-                    return new QIRBuiltin(src, "sum");
                 case "new.tableRef":
                     final QIRVariable tableName = new QIRVariable(null, "__tmp__");
                     final QIRVariable schemaName = new QIRVariable(null, "__tmp2__");
@@ -263,6 +264,30 @@ public final class QIRInterface {
                                                     new QIRLambda(null, null, schemaName, new QIRTable<>(null, tableName, schemaName, null), new FrameDescriptor()), new FrameDescriptor()),
                                                     new FrameDescriptor()),
                                     new FrameDescriptor());
+                case "sum":
+                case "min":
+                case "max":
+                case "date":
+                    return new QIRBuiltin(src, fun.getName());
+                case "substr":
+                    return new QIRBuiltin(src, "substring");
+                case "mean":
+                    return new QIRBuiltin(src, "avg");
+                case "length":
+                    return new QIRBuiltin(src, "count");
+                case "match":
+                    return new QIRBuiltin(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 QIRBuiltin(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 QIRBuiltin(src, "like"), y), x), new FrameDescriptor()),
+                                    new FrameDescriptor());
                 default:
                     return RFunctionToQIRType(src, fun.getName(), (FunctionDefinitionNode) fun.getRootNode());
             }
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
index 16a0667b4c..c3f84fc3cc 100644
--- 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
@@ -25,7 +25,9 @@ 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.*;
@@ -135,7 +137,6 @@ public final class QIRTranslateVisitor implements RSyntaxNodeVisitor<QIRNode> {
 
     @Override
     public final QIRNode visit(final RCallNode call) {
-        // TODO: Remove this hack
         try {
             return visitBuiltin(call.getSourceSection(), ((ReadVariableNode) call.getFunction()).getIdentifier(),
                             Arrays.stream(call.getArguments().getArguments()).map(arg -> arg.accept(this)).collect(Collectors.toList()));
@@ -154,12 +155,18 @@ public final class QIRTranslateVisitor implements RSyntaxNodeVisitor<QIRNode> {
     }
 
     @Override
-    public final QIRNode visit(final RCallSpecialNode dot) {
-        return visitBuiltin(dot.getSourceSection(), dot.expectedFunction.getName(), Arrays.stream(dot.getSyntaxArguments()).map(arg -> ((RSyntaxNode) arg).accept(this)).collect(Collectors.toList()));
+    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 "+":
@@ -172,6 +179,8 @@ public final class QIRTranslateVisitor implements RSyntaxNodeVisitor<QIRNode> {
                 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));
@@ -188,6 +197,9 @@ public final class QIRTranslateVisitor implements RSyntaxNodeVisitor<QIRNode> {
                 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);
         }
@@ -229,7 +241,11 @@ public final class QIRTranslateVisitor implements RSyntaxNodeVisitor<QIRNode> {
 
     @Override
     public final QIRNode visit(final ROrderNode order) {
-        return new QIRSortBy(order.getSourceSection(), order.getOrder().asRSyntaxNode().accept(this), order.getIsAscending().asRSyntaxNode().accept(this),
+        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));
     }
 
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 ab20ce2a42..317c4174ab 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
@@ -417,6 +417,10 @@ query returns [T 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]
@@ -575,7 +579,11 @@ BREAK  : 'break' ;
 SELECT : 'select' ;
 FROM : 'from' ;
 WHERE : 'where' ;
-GROUP : 'groupby' ;
+GROUP : 'group' ;
+ORDER : 'order' ;
+JOIN : 'join' ;
+LJOIN : 'leftJoin' ;
+RJOIN : '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/nodes/RCodeBuilder.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java
index 9d2bdff63a..968444aeb9 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
@@ -115,10 +115,30 @@ public interface RCodeBuilder<T> {
     T where(final SourceSection source, final T filter, final T child);
 
     /**
-     * Creates a where query.
+     * 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).
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
index 5eb6ed21c8..8cb379d105 100644
--- 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
@@ -44,21 +44,21 @@ public final class RTestSuite {
                             System.out.println("Testing: " + file);
                             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
                             final String expected;
-                            try {
-                                RscriptCommand.doMain(new String[]{file.toString()}, null, true, System.in, new PrintStream(baos));
-                                // Unreachable code from here, because main will try to exit which
-                                // will cause a SecurityException
-                            } catch (SecurityException e) {
-                            }
                             try {
                                 expected = String.join("\n", Files.readAllLines(Paths.get(file.toString().replaceFirst("\\.[Rr]", ".out"))));
-                                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());
+                                try {
+                                    RscriptCommand.doMain(new String[]{file.toString()}, null, true, System.in, new PrintStream(baos));
+                                    // Unreachable code from here, because main will try to exit
+                                    // which will cause a SecurityException
+                                } catch (SecurityException e) {
+                                    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.");
diff --git a/com.oracle.truffle.r.test/tests/hbase/QueryGroup.R b/com.oracle.truffle.r.test/tests/hbase/QueryGroup.R
index 48064f5148..edd7aba5db 100644
--- a/com.oracle.truffle.r.test/tests/hbase/QueryGroup.R
+++ b/com.oracle.truffle.r.test/tests/hbase/QueryGroup.R
@@ -1,5 +1,5 @@
 emp = new.tableRef("emp", "HBase", "hbase-site.xml", "default")
-q = groupby(function (x) c(x$deptno),
+q = group(function (x) c(x$deptno),
     select(function (x) {
              res = new.env()
              res$deptno = x$deptno
diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunction.out b/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunction.out
index 5a93e98e48..e8791d46bb 100644
--- a/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunction.out
+++ b/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunction.out
@@ -1,7 +1,7 @@
-  ename empno salary
-1 SMITH     1   2225
-2  WARD     3   4645
-3 JONES     4   3115
-4 SCOTT     8   3769
-5 ADAMS    11   4450
+  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.out b/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunctionWithDeps.out
index 5a93e98e48..e8791d46bb 100644
--- a/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunctionWithDeps.out
+++ b/com.oracle.truffle.r.test/tests/pgsql/QueryCallFunctionWithDeps.out
@@ -1,7 +1,7 @@
-  ename empno salary
-1 SMITH     1   2225
-2  WARD     3   4645
-3 JONES     4   3115
-4 SCOTT     8   3769
-5 ADAMS    11   4450
+  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
index e6d7522634..3d5c90e636 100644
--- a/com.oracle.truffle.r.test/tests/pgsql/QueryGroup.R
+++ b/com.oracle.truffle.r.test/tests/pgsql/QueryGroup.R
@@ -1,5 +1,5 @@
 emp = new.tableRef("emp", "PostgreSQL", "postgre.config", "public")
-q = groupby(function (x) c(x$deptno),
+q = group(function (x) c(x$deptno),
     select(function (x) {
              res = new.env()
              res$deptno = x$deptno
diff --git a/com.oracle.truffle.r.test/tests/pgsql/QueryLambda.out b/com.oracle.truffle.r.test/tests/pgsql/QueryLambda.out
index 5a93e98e48..e8791d46bb 100644
--- a/com.oracle.truffle.r.test/tests/pgsql/QueryLambda.out
+++ b/com.oracle.truffle.r.test/tests/pgsql/QueryLambda.out
@@ -1,7 +1,7 @@
-  ename empno salary
-1 SMITH     1   2225
-2  WARD     3   4645
-3 JONES     4   3115
-4 SCOTT     8   3769
-5 ADAMS    11   4450
+  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/tpch/QueryTPCH1.R b/com.oracle.truffle.r.test/tests/tpch/QueryTPCH1.R
new file mode 100644
index 0000000000..8e483ac8af
--- /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 0000000000..79e850acaf
--- /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 0000000000..eb4750784a
--- /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 0000000000..379f087147
--- /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 0000000000..f2142740a0
--- /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 0000000000..0140252c33
--- /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 0000000000..ed31330255
--- /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 0000000000..56a0ee187b
--- /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 0000000000..ea4cd6869f
--- /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 0000000000..35d78e4d6e
--- /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 0000000000..07a9334476
--- /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 0000000000..5724bd455b
--- /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 0000000000..ead3515106
--- /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 0000000000..1914b57df3
--- /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 0000000000..505ac5a29a
--- /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 0000000000..f00c9d86ed
--- /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 0000000000..6304085758
--- /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 0000000000..8acb494b28
--- /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 0000000000..e34f5c8ff1
--- /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 0000000000..9fe1b33cec
--- /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 0000000000..4db3d200ab
--- /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 0000000000..af28bf1a26
--- /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 0000000000..027104f14e
--- /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 527fa89155..b9a1e717f2 100644
--- a/mx.fastr/suite.py
+++ b/mx.fastr/suite.py
@@ -84,6 +84,16 @@ suite = {
       "sha1" : "NOCHECK",
     },
 
+    "QIR" : {
+      "path" : "../qir/qir.jar",
+      "sha1" : "NOCHECK",
+    },
+
+    "PGSQL" : {
+      "path" : "../truffle/lib/postgresql.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"],
@@ -128,6 +138,7 @@ suite = {
       "dependencies" : [
         "com.oracle.truffle.r.runtime",
         "truffle:TRUFFLE_DEBUG",
+        "QIR"
       ],
       "checkstyle" : "com.oracle.truffle.r.runtime",
       "javaCompliance" : "1.8",
@@ -142,6 +153,7 @@ suite = {
       "sourceDirs" : ["src"],
       "dependencies" : [
         "com.oracle.truffle.r.library",
+        "QIR"
       ],
       "checkstyle" : "com.oracle.truffle.r.runtime",
       "javaCompliance" : "1.8",
@@ -197,6 +209,8 @@ suite = {
         "com.oracle.truffle.r.parser",
         "truffle:JLINE",
         "truffle:TRUFFLE_DEBUG",
+        "QIR",
+        "PGSQL"
       ],
      "generatedDependencies" : [
         "com.oracle.truffle.r.parser",
@@ -217,6 +231,7 @@ suite = {
         "truffle:TRUFFLE_API",
         "truffle:TRUFFLE_DEBUG",
         "XZ-1.5",
+        "QIR"
       ],
       "checkstyle" : "com.oracle.truffle.r.runtime",
       "javaCompliance" : "1.8",
@@ -416,4 +431,3 @@ suite = {
     },
   },
 }
-
diff --git a/oracle.config b/oracle.config
new file mode 100644
index 0000000000..b49e79d8cb
--- /dev/null
+++ b/oracle.config
@@ -0,0 +1,5 @@
+ora.host = myoracle.com
+ora.sid = myview
+ora.port = 7658
+ora.user = julilope
+ora.passwd = AVONEJ$sartec3
diff --git a/postgre.config b/postgre.config
new file mode 100644
index 0000000000..e0fd542200
--- /dev/null
+++ b/postgre.config
@@ -0,0 +1,5 @@
+pgsql.host = localhost
+pgsql.sid = postgres
+pgsql.port = 5432
+pgsql.user = julien
+pgsql.passwd = Pa$$w0rd
diff --git a/postgre2.config b/postgre2.config
new file mode 100644
index 0000000000..2c7bf36535
--- /dev/null
+++ b/postgre2.config
@@ -0,0 +1,5 @@
+pgsql.host = localhost
+pgsql.sid = other
+pgsql.port = 5432
+pgsql.user = julien
+pgsql.passwd = Pa$$w0rd
-- 
GitLab