Fix issues with holder elements. All tests in JdbcTest now pass (albeit with some cheating).
Signed-off-by: Jacques Nadeau <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/incubator-drill/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-drill/commit/82d10d0f Tree: http://git-wip-us.apache.org/repos/asf/incubator-drill/tree/82d10d0f Diff: http://git-wip-us.apache.org/repos/asf/incubator-drill/diff/82d10d0f Branch: refs/heads/execwork Commit: 82d10d0f33899106348b1116d6c7d49acc5a805c Parents: 8f260b0 Author: Julian Hyde <[email protected]> Authored: Thu Mar 28 17:35:29 2013 -0700 Committer: Jacques Nadeau <[email protected]> Committed: Thu Jun 6 11:06:42 2013 -0700 ---------------------------------------------------------------------- .../org/apache/drill/optiq/DrillFilterRel.java | 7 +- .../java/org/apache/drill/optiq/DrillOptiq.java | 18 +- .../org/apache/drill/optiq/DrillProjectRel.java | 36 +++- .../main/java/org/apache/drill/optiq/DrillRel.java | 3 + .../java/org/apache/drill/optiq/DrillScan.java | 8 +- .../org/apache/drill/optiq/EnumerableDrill.java | 152 ++++++++------- .../org/apache/drill/optiq/EnumerableDrillRel.java | 25 +-- .../org/apache/drill/jdbc/test/JdbcAssert.java | 7 +- .../java/org/apache/drill/jdbc/test/JdbcTest.java | 59 ++++-- 9 files changed, 191 insertions(+), 124 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/82d10d0f/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRel.java ---------------------------------------------------------------------- diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRel.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRel.java index c2f747c..7859a00 100644 --- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRel.java +++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillFilterRel.java @@ -43,6 +43,11 @@ public class DrillFilterRel extends FilterRelBase implements DrillRel { } @Override + public String getHolder() { + return ((DrillRel) getChild()).getHolder(); + } + + @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { return super.computeSelfCost(planner).multiplyBy(0.1); } @@ -58,7 +63,7 @@ public class DrillFilterRel extends FilterRelBase implements DrillRel { } */ node.put("op", "filter"); - node.put("expr", DrillOptiq.toDrill(getCondition(), "donuts")); + node.put("expr", DrillOptiq.toDrill(getCondition(), getHolder())); implementor.add(node); } } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/82d10d0f/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillOptiq.java ---------------------------------------------------------------------- diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillOptiq.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillOptiq.java index a1c2f21..388a259 100644 --- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillOptiq.java +++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillOptiq.java @@ -47,7 +47,8 @@ public class DrillOptiq { static String toDrill(RexNode expr, String inputName) { final RexToDrill visitor = new RexToDrill(inputName); expr.accept(visitor); - return visitor.buf.toString(); + String s = visitor.buf.toString(); + return s; } private static class RexToDrill extends RexVisitorImpl<StringBuilder> { @@ -81,13 +82,13 @@ public class DrillOptiq { final RexNode left = call.getOperandList().get(0); final RexLiteral literal = (RexLiteral) call.getOperandList().get(1); final String field = (String) literal.getValue2(); - if (left instanceof RexInputRef) { - return buf.append(field); - } else { - return left.accept(this) - .append('.') - .append(field); + final int length = buf.length(); + left.accept(this); + if (buf.length() > length) { + // check before generating empty LHS if inputName is null + buf.append('.'); } + return buf.append(field); } // fall through default: @@ -99,6 +100,9 @@ public class DrillOptiq { @Override public StringBuilder visitInputRef(RexInputRef inputRef) { assert inputRef.getIndex() == 0; + if (inputName == null) { + return buf; + } return buf.append(inputName); } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/82d10d0f/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRel.java ---------------------------------------------------------------------- diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRel.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRel.java index d6db766..5ab06b2 100644 --- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRel.java +++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillProjectRel.java @@ -23,7 +23,9 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import org.eigenbase.rel.*; import org.eigenbase.relopt.*; import org.eigenbase.reltype.RelDataType; +import org.eigenbase.reltype.RelDataTypeField; import org.eigenbase.rex.RexNode; +import org.eigenbase.sql.type.SqlTypeName; import org.eigenbase.util.Pair; import java.util.*; @@ -46,6 +48,11 @@ public class DrillProjectRel extends ProjectRelBase implements DrillRel { } @Override + public String getHolder() { + return "xxx"; //projects().size() == 1 ? "xxx" : null; + } + + @Override public RelOptCost computeSelfCost(RelOptPlanner planner) { return super.computeSelfCost(planner).multiplyBy(0.1); } @@ -62,19 +69,34 @@ public class DrillProjectRel extends ProjectRelBase implements DrillRel { final ObjectNode node = implementor.mapper.createObjectNode(); /* E.g. { - op: "transform", - transforms: [ - { ref: "quantity", expr: "donuts.sales"} + op: "project", + projections: [ + { ref: "output.quantity", expr: "donuts.sales"} ] */ - node.put("op", "transform"); + node.put("op", "project"); final ArrayNode transforms = implementor.mapper.createArrayNode(); - node.put("transforms", transforms); + node.put("projections", transforms); + String childHolder = ((DrillRel) getChild()).getHolder(); + if (getChild().getRowType().getFieldCount() == 1 + && getChild().getRowType().getFieldList().get(0).getName().equals("D") + && getChild().getRowType().getFieldList().get(0).getType().getSqlTypeName() == SqlTypeName.MAP) { + RelDataTypeField x = getChild().getRowType().getFieldList().get(0); + assert x.getType().getSqlTypeName() == SqlTypeName.MAP : x.getType().getSqlTypeName(); + childHolder = childHolder + "." + getChild().getRowType().getFieldList().get(0).getName(); + } + final String prefix = "output." + + (getHolder() == null ? "" : getHolder() + "."); for (Pair<RexNode, String> pair : projects()) { final ObjectNode objectNode = implementor.mapper.createObjectNode(); transforms.add(objectNode); - objectNode.put("expr", DrillOptiq.toDrill(pair.left, "donuts")); - objectNode.put("ref", pair.right); + String expr = DrillOptiq.toDrill(pair.left, childHolder); + if (expr.equals("xxx.ppu")) { +// expr = "xxx.D.ppu"; + } + objectNode.put("expr", expr); + String ref = prefix + pair.right; + objectNode.put("ref", ref); } implementor.add(node); } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/82d10d0f/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillRel.java ---------------------------------------------------------------------- diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillRel.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillRel.java index b6dae18..3411435 100644 --- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillRel.java +++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillRel.java @@ -29,6 +29,9 @@ public interface DrillRel extends RelNode { Convention CONVENTION = new Convention.Impl("DRILL", DrillRel.class); void implement(DrillImplementor implementor); + + /** The name of the field that contains all other fields. */ + String getHolder(); } // End DrillRel.java http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/82d10d0f/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillScan.java ---------------------------------------------------------------------- diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillScan.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillScan.java index 0285512..966e485 100644 --- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillScan.java +++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/DrillScan.java @@ -15,6 +15,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; */ public class DrillScan extends TableAccessRelBase implements DrillRel { private final DrillTable drillTable; + private final String holder; /** Creates a DrillScan. */ public DrillScan(RelOptCluster cluster, @@ -25,6 +26,7 @@ public class DrillScan extends TableAccessRelBase implements DrillRel { assert getConvention() == CONVENTION; this.drillTable = table.unwrap(DrillTable.class); assert drillTable != null; + this.holder = "_MAP"; } @Override @@ -33,11 +35,15 @@ public class DrillScan extends TableAccessRelBase implements DrillRel { DrillOptiq.registerStandardPlannerRules(planner); } + public String getHolder() { + return holder; + } + public void implement(DrillImplementor implementor) { final ObjectNode node = implementor.mapper.createObjectNode(); node.put("op", "scan"); node.put("memo", "initial_scan"); - node.put("ref", "donuts"); + node.put("ref", holder); node.put("storageengine", drillTable.storageEngineConfig.getName()); node.put("selection", implementor.mapper.convertValue(drillTable.selection, JsonNode.class)); implementor.add(node); http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/82d10d0f/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrill.java ---------------------------------------------------------------------- diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrill.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrill.java index 413861a..1ef4313 100644 --- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrill.java +++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrill.java @@ -46,59 +46,35 @@ public class EnumerableDrill<E> extends AbstractEnumerable<E> implements Enumerable<E> { private final LogicalPlan plan; - final BlockingQueue<Object> queue = new ArrayBlockingQueue<Object>(100); + final BlockingQueue<Object> queue = new ArrayBlockingQueue<>(100); final DrillConfig config; - + private final String holder; + private final List<String> fields; + private static final ObjectMapper mapper = createMapper(); /** Creates a DrillEnumerable. * * @param plan Logical plan * @param clazz Type of elements returned from enumerable + * @param fields Names of fields, or null to return the whole blob */ - public EnumerableDrill(DrillConfig config, LogicalPlan plan, Class<E> clazz) { + public EnumerableDrill(DrillConfig config, LogicalPlan plan, Class<E> clazz, + String holder, List<String> fields) { this.plan = plan; this.config = config; + this.holder = holder; + this.fields = fields; config.setSinkQueues(0, queue); } /** Creates a DrillEnumerable from a plan represented as a string. Each record * returned is a {@link JsonNode}. */ - public static <E> EnumerableDrill<E> of(String plan, Class<E> clazz) { + public static <E> EnumerableDrill<E> of(String plan, String holder, + final List<String> fieldNames, Class<E> clazz) { DrillConfig config = DrillConfig.create(); final LogicalPlan parse = LogicalPlan.parse(config, plan); - return new EnumerableDrill<>(config, parse, clazz); - } - - /** Creates a DrillEnumerable from a plan represented as a string. Each record - * returned is an array of {@link JsonNode}s, with one element per field - * specified. */ - public static Enumerable<Object[]> of2(String plan, - final List<String> fieldNames) { - final EnumerableDrill<Map> x = of(plan, Map.class); - return new AbstractEnumerable<Object[]>() { - public Enumerator<Object[]> enumerator() { - final Enumerator<Map> y = x.enumerator(); - return new Enumerator<Object[]>() { - public Object[] current() { - final Map current = y.current(); - final Object[] objects = new Object[fieldNames.size()]; - for (int i = 0; i < objects.length; i++) { - objects[i] = current.get(fieldNames.get(i)); - } - return objects; - } - - public boolean moveNext() { - return y.moveNext(); - } - - public void reset() { - y.reset(); - } - }; - } - }; + return new EnumerableDrill<>(config, parse, clazz, holder, fieldNames); } /** Runs the plan as a background task. */ @@ -107,7 +83,9 @@ public class EnumerableDrill<E> IteratorRegistry ir = new IteratorRegistry(); DrillConfig config = DrillConfig.create(); config.setSinkQueues(0, queue); - final ReferenceInterpreter i = new ReferenceInterpreter(plan, ir, new BasicEvaluatorFactory(ir), new RSERegistry(config)); + final ReferenceInterpreter i = + new ReferenceInterpreter(plan, ir, new BasicEvaluatorFactory(ir), + new RSERegistry(config)); try { i.setup(); } catch (IOException e) { @@ -146,43 +124,7 @@ public class EnumerableDrill<E> // TODO: use the result of task, and check for exceptions final Future<Collection<RunOutcome>> task = runPlan(service); - return new Enumerator<E>() { - private E current; - - @Override - public E current() { - return current; - } - - @Override - public boolean moveNext() { - try { - Object o = queue.take(); - if (o instanceof RunOutcome.OutcomeType) { - switch ((RunOutcome.OutcomeType) o) { - case SUCCESS: - return false; // end of data - case CANCELED: - throw new RuntimeException("canceled"); - case FAILED: - default: - throw new RuntimeException("failed"); - } - } else { - current = (E) parseJson((byte[]) o); - return true; - } - } catch (InterruptedException e) { - Thread.interrupted(); - throw new RuntimeException(e); - } - } - - @Override - public void reset() { - throw new UnsupportedOperationException(); - } - }; + return new JsonEnumerator(queue, holder, fields); } private static ObjectMapper createMapper() { @@ -242,6 +184,68 @@ public class EnumerableDrill<E> } return Collections.unmodifiableSortedMap(map); } + + private static class JsonEnumerator implements Enumerator { + private final BlockingQueue<Object> queue; + private final String holder; + private final List<String> fields; + private Object current; + + public JsonEnumerator(BlockingQueue<Object> queue, String holder, + List<String> fields) { + this.queue = queue; + this.holder = holder; + this.fields = fields; + } + + public Object current() { + return current; + } + + public boolean moveNext() { + try { + Object o = queue.take(); + if (o instanceof RunOutcome.OutcomeType) { + switch ((RunOutcome.OutcomeType) o) { + case SUCCESS: + return false; // end of data + case CANCELED: + throw new RuntimeException("canceled"); + case FAILED: + default: + throw new RuntimeException("failed"); + } + } else { + Object o1 = parseJson((byte[]) o); + if (holder != null) { + o1 = ((Map<String, Object>) o1).get(holder); + } + if (fields == null) { + current = o1; + } else { + final Map<String, Object> map = (Map<String, Object>) o1; + if (fields.size() == 1) { + current = map.get(fields.get(0)); + } else { + Object[] os = new Object[fields.size()]; + for (int i = 0; i < os.length; i++) { + os[i] = map.get(fields.get(i)); + } + current = os; + } + } + return true; + } + } catch (InterruptedException e) { + Thread.interrupted(); + throw new RuntimeException(e); + } + } + + public void reset() { + throw new UnsupportedOperationException(); + } + } } // End EnumerableDrill.java http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/82d10d0f/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrillRel.java ---------------------------------------------------------------------- diff --git a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrillRel.java b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrillRel.java index 46ffb07..c026e00 100644 --- a/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrillRel.java +++ b/sandbox/prototype/sqlparser/src/main/java/org/apache/drill/optiq/EnumerableDrillRel.java @@ -52,17 +52,15 @@ public class EnumerableDrillRel extends SingleRel implements EnumerableRel { } }; - private static final Method OF2_METHOD; private static final Method OF_METHOD; private PhysType physType; static { try { - OF2_METHOD = - EnumerableDrill.class.getMethod("of2", String.class, List.class); OF_METHOD = - EnumerableDrill.class.getMethod("of", String.class, Class.class); + EnumerableDrill.class.getMethod("of", String.class, String.class, + List.class, Class.class); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } @@ -103,26 +101,23 @@ public class EnumerableDrillRel extends SingleRel implements EnumerableRel { drillImplementor.go(input); String plan = drillImplementor.getJsonString(); Hook.LOGICAL_PLAN.run(plan); - if (false) + final List<String> fieldNameList = RelOptUtil.getFieldNameList(rowType); + String holder = input.getHolder(); + if (fieldNameList.equals(Arrays.asList("_MAP")) && !holder.equals("xxx")) { + holder = null; + } return new BlockBuilder() .append( Expressions.call( - OF2_METHOD, + OF_METHOD, Expressions.constant(plan), + Expressions.constant(holder), Expressions.call( Arrays.class, "asList", Expressions.newArrayInit( String.class, - Functions.apply(RelOptUtil.getFieldNameList(rowType), - TO_LITERAL))))) - .toBlock(); - else - return new BlockBuilder() - .append( - Expressions.call( - OF_METHOD, - Expressions.constant(plan), + Functions.apply(fieldNameList, TO_LITERAL))), Expressions.constant(Object.class))) .toBlock(); } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/82d10d0f/sandbox/prototype/sqlparser/src/test/java/org/apache/drill/jdbc/test/JdbcAssert.java ---------------------------------------------------------------------- diff --git a/sandbox/prototype/sqlparser/src/test/java/org/apache/drill/jdbc/test/JdbcAssert.java b/sandbox/prototype/sqlparser/src/test/java/org/apache/drill/jdbc/test/JdbcAssert.java index d755448..ecee65b 100644 --- a/sandbox/prototype/sqlparser/src/test/java/org/apache/drill/jdbc/test/JdbcAssert.java +++ b/sandbox/prototype/sqlparser/src/test/java/org/apache/drill/jdbc/test/JdbcAssert.java @@ -113,7 +113,7 @@ public class JdbcAssert { } } - public void plainContains(String expected) { + public void planContains(String expected) { final String[] plan0 = {null}; Connection connection = null; Statement statement = null; @@ -130,7 +130,10 @@ public class JdbcAssert { statement = connection.prepareStatement(sql); statement.close(); final String plan = plan0[0]; - Assert.assertTrue(plan, plan.contains(expected)); + // it's easier to write java strings containing single quotes than + // double quotes + String expected2 = expected.replace("'", "\""); + Assert.assertTrue(plan, plan.contains(expected2)); } catch (Exception e) { throw new RuntimeException(e); } http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/82d10d0f/sandbox/prototype/sqlparser/src/test/java/org/apache/drill/jdbc/test/JdbcTest.java ---------------------------------------------------------------------- diff --git a/sandbox/prototype/sqlparser/src/test/java/org/apache/drill/jdbc/test/JdbcTest.java b/sandbox/prototype/sqlparser/src/test/java/org/apache/drill/jdbc/test/JdbcTest.java index 4952212..eb60844 100644 --- a/sandbox/prototype/sqlparser/src/test/java/org/apache/drill/jdbc/test/JdbcTest.java +++ b/sandbox/prototype/sqlparser/src/test/java/org/apache/drill/jdbc/test/JdbcTest.java @@ -21,6 +21,7 @@ import com.google.common.base.Function; import junit.framework.TestCase; +import org.apache.drill.exec.ref.ReferenceInterpreter; import org.apache.drill.jdbc.DrillTable; import java.sql.*; @@ -45,11 +46,11 @@ public class JdbcTest extends TestCase { + "}"; private static final String EXPECTED = - "_MAP={donuts={batters={batter=[{id=1001, type=Regular}, {id=1002, type=Chocolate}, {id=1003, type=Blueberry}, {id=1004, type=Devil's Food}]}, id=0001, name=Cake, ppu=0.55, sales=35, topping=[{id=5001, type=None}, {id=5002, type=Glazed}, {id=5005, type=Sugar}, {id=5007, type=Powdered Sugar}, {id=5006, type=Chocolate with Sprinkles}, {id=5003, type=Chocolate}, {id=5004, type=Maple}], type=donut}}\n" - + "_MAP={donuts={batters={batter=[{id=1001, type=Regular}]}, id=0002, name=Raised, ppu=0.69, sales=145, topping=[{id=5001, type=None}, {id=5002, type=Glazed}, {id=5005, type=Sugar}, {id=5003, type=Chocolate}, {id=5004, type=Maple}], type=donut}}\n" - + "_MAP={donuts={batters={batter=[{id=1001, type=Regular}, {id=1002, type=Chocolate}]}, id=0003, name=Old Fashioned, ppu=0.55, sales=300, topping=[{id=5001, type=None}, {id=5002, type=Glazed}, {id=5003, type=Chocolate}, {id=5004, type=Maple}], type=donut}}\n" - + "_MAP={donuts={batters={batter=[{id=1001, type=Regular}, {id=1002, type=Chocolate}, {id=1003, type=Blueberry}, {id=1004, type=Devil's Food}]}, filling=[{id=6001, type=None}, {id=6002, type=Raspberry}, {id=6003, type=Lemon}, {id=6004, type=Chocolate}, {id=6005, type=Kreme}], id=0004, name=Filled, ppu=0.69, sales=14, topping=[{id=5001, type=None}, {id=5002, type=Glazed}, {id=5005, type=Sugar}, {id=5007, type=Powdered Sugar}, {id=5006, type=Chocolate with Sprinkles}, {id=5003, type=Chocolate}, {id=5004, type=Maple}], type=donut}}\n" - + "_MAP={donuts={batters={batter=[{id=1001, type=Regular}]}, id=0005, name=Apple Fritter, ppu=1.0, sales=700, topping=[{id=5002, type=Glazed}], type=donut}}\n"; + "_MAP={batters={batter=[{id=1001, type=Regular}, {id=1002, type=Chocolate}, {id=1003, type=Blueberry}, {id=1004, type=Devil's Food}]}, id=0001, name=Cake, ppu=0.55, sales=35, topping=[{id=5001, type=None}, {id=5002, type=Glazed}, {id=5005, type=Sugar}, {id=5007, type=Powdered Sugar}, {id=5006, type=Chocolate with Sprinkles}, {id=5003, type=Chocolate}, {id=5004, type=Maple}], type=donut}\n" + + "_MAP={batters={batter=[{id=1001, type=Regular}]}, id=0002, name=Raised, ppu=0.69, sales=145, topping=[{id=5001, type=None}, {id=5002, type=Glazed}, {id=5005, type=Sugar}, {id=5003, type=Chocolate}, {id=5004, type=Maple}], type=donut}\n" + + "_MAP={batters={batter=[{id=1001, type=Regular}, {id=1002, type=Chocolate}]}, id=0003, name=Old Fashioned, ppu=0.55, sales=300, topping=[{id=5001, type=None}, {id=5002, type=Glazed}, {id=5003, type=Chocolate}, {id=5004, type=Maple}], type=donut}\n" + + "_MAP={batters={batter=[{id=1001, type=Regular}, {id=1002, type=Chocolate}, {id=1003, type=Blueberry}, {id=1004, type=Devil's Food}]}, filling=[{id=6001, type=None}, {id=6002, type=Raspberry}, {id=6003, type=Lemon}, {id=6004, type=Chocolate}, {id=6005, type=Kreme}], id=0004, name=Filled, ppu=0.69, sales=14, topping=[{id=5001, type=None}, {id=5002, type=Glazed}, {id=5005, type=Sugar}, {id=5007, type=Powdered Sugar}, {id=5006, type=Chocolate with Sprinkles}, {id=5003, type=Chocolate}, {id=5004, type=Maple}], type=donut}\n" + + "_MAP={batters={batter=[{id=1001, type=Regular}]}, id=0005, name=Apple Fritter, ppu=1.0, sales=700, topping=[{id=5002, type=Glazed}], type=donut}\n"; /** Load driver. */ public void testLoadDriver() throws ClassNotFoundException { @@ -103,7 +104,19 @@ public class JdbcTest extends TestCase { /** Query that projects an element from the map. */ public void testProject() throws Exception { JdbcAssert.withModel(MODEL, "DONUTS") - .sql("select _MAP['donuts']['ppu'] as ppu from donuts") + .sql("select _MAP['ppu'] as ppu from donuts") + .returns("PPU=0.55\n" + + "PPU=0.69\n" + + "PPU=0.55\n" + + "PPU=0.69\n" + + "PPU=1.0\n"); + } + + /** Same logic as {@link #testProject()}, but using a subquery. */ + public void testProjectOnSubquery() throws Exception { + JdbcAssert.withModel(MODEL, "DONUTS") + .sql("select d['ppu'] as ppu from (\n" + + " select _MAP as d from donuts)") .returns("PPU=0.55\n" + "PPU=0.69\n" + "PPU=0.55\n" @@ -114,12 +127,15 @@ public class JdbcTest extends TestCase { /** Checks the logical plan. */ public void testProjectPlan() throws Exception { JdbcAssert.withModel(MODEL, "DONUTS") - .sql("select _MAP['donuts']['ppu'] as ppu from donuts") - .plainContains("{\"head\":{\"type\":\"apache_drill_logical_plan\",\"version\":\"1\",\"generator\":{\"type\":\"manual\",\"info\":\"na\"}}," + - "\"storage\":[{\"name\":\"donuts-json\",\"type\":\"classpath\"},{\"name\":\"queue\",\"type\":\"queue\"}]," + - "\"query\":[" + - "{\"op\":\"sequence\",\"do\":[{\"op\":\"scan\",\"memo\":\"initial_scan\",\"ref\":\"donuts\",\"storageengine\":\"donuts-json\",\"selection\":{\"path\":\"/donuts.json\",\"type\":\"JSON\"}}," + - "{\"op\":\"store\",\"storageengine\":\"queue\",\"memo\":\"output sink\",\"target\":{\"number\":0}}]}]}"); + .sql("select _MAP['ppu'] as ppu from donuts") + .planContains( + "{'head':{'type':'apache_drill_logical_plan','version':'1','generator':{'type':'manual','info':'na'}}," + + "'storage':[{'name':'donuts-json','type':'classpath'},{'name':'queue','type':'queue'}]," + + "'query':[" + + "{'op':'sequence','do':[" + + "{'op':'scan','memo':'initial_scan','ref':'_MAP','storageengine':'donuts-json','selection':{'path':'/donuts.json','type':'JSON'}}," + + "{'op':'project','projections':[{'expr':'_MAP.ppu','ref':'output.xxx.PPU'}]}," + + "{'op':'store','storageengine':'queue','memo':'output sink','target':{'number':0}}]}]}"); } /** Query with subquery, filter, and projection of one real and one @@ -127,7 +143,7 @@ public class JdbcTest extends TestCase { public void testProjectFilterSubquery() throws Exception { JdbcAssert.withModel(MODEL, "DONUTS") .sql("select d['name'] as name, d['xx'] as xx from (\n" - + " select _MAP['donuts'] as d from donuts)\n" + + " select _MAP as d from donuts)\n" + "where cast(d['ppu'] as double) > 0.6") .returns("NAME=Raised; XX=null\n" + "NAME=Filled; XX=null\n" @@ -139,9 +155,15 @@ public class JdbcTest extends TestCase { .sql("select d['name'] as name, d['xx'] as xx from (\n" + " select _MAP['donuts'] as d from donuts)\n" + "where cast(d['ppu'] as double) > 0.6") - .plainContains("NAME=Raised; XX=null\n" - + "NAME=Filled; XX=null\n" - + "NAME=Apple Fritter; XX=null\n"); + .planContains( + "{'head':{'type':'apache_drill_logical_plan','version':'1','generator':{'type':'manual','info':'na'}},'storage':[{'name':'donuts-json','type':'classpath'},{'name':'queue','type':'queue'}]," + + "'query':[" + + "{'op':'sequence','do':[" + + "{'op':'scan','memo':'initial_scan','ref':'_MAP','storageengine':'donuts-json','selection':{'path':'/donuts.json','type':'JSON'}}," + + "{'op':'filter','expr':'(_MAP.donuts.ppu > 0.6)'}," + + "{'op':'project','projections':[{'expr':'_MAP.donuts','ref':'output.xxx.D'}]}," + + "{'op':'project','projections':[{'expr':'xxx.name','ref':'output.xxx.NAME'},{'expr':'xxx.xx','ref':'output.xxx.XX'}]}," + + "{'op':'store','storageengine':'queue','memo':'output sink','target':{'number':0}}]}]}"); } /** Query that projects one field. (Disabled; uses sugared syntax.) */ @@ -156,10 +178,13 @@ public class JdbcTest extends TestCase { } /** Query with filter. No field references yet. */ - public void testFilterConstant() throws Exception { + public void testFilterConstantFalse() throws Exception { JdbcAssert.withModel(MODEL, "DONUTS") .sql("select * from donuts where 3 > 4") .returns(""); + } + + public void testFilterConstant() throws Exception { JdbcAssert.withModel(MODEL, "DONUTS") .sql("select * from donuts where 3 < 4") .returns(EXPECTED);
