You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@drill.apache.org by vo...@apache.org on 2021/08/05 17:23:23 UTC
[drill] 10/13: Additional cleanup
This is an automated email from the ASF dual-hosted git repository.
volodymyr pushed a commit to branch mongo
in repository https://gitbox.apache.org/repos/asf/drill.git
commit ba71548c121099f75ecbdbc00f3cf1851ccc94a2
Author: Volodymyr Vysotskyi <vv...@gmail.com>
AuthorDate: Sat Jul 31 22:37:59 2021 +0300
Additional cleanup
---
.../exec/store/mongo/MongoAggregateUtils.java | 4 +-
.../drill/exec/store/mongo/MongoFilterBuilder.java | 68 +++---
.../store/mongo/MongoPushDownFilterForScan.java | 96 --------
.../store/mongo/plan/MongoPluginImplementor.java | 146 +------------
.../drill/exec/store/mongo/plan/MongoRules.java | 243 ---------------------
.../store/mongo/plan/RexToMongoTranslator.java | 184 ++++++++++++++++
6 files changed, 223 insertions(+), 518 deletions(-)
diff --git a/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/MongoAggregateUtils.java b/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/MongoAggregateUtils.java
index 817644d..e362707 100644
--- a/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/MongoAggregateUtils.java
+++ b/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/MongoAggregateUtils.java
@@ -34,14 +34,14 @@ public class MongoAggregateUtils {
return SqlValidatorUtil.uniquify(renamed, true);
}
- static String maybeQuote(String s) {
+ public static String maybeQuote(String s) {
if (!needsQuote(s)) {
return s;
}
return quote(s);
}
- static String quote(String s) {
+ public static String quote(String s) {
return "'" + s + "'";
}
diff --git a/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/MongoFilterBuilder.java b/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/MongoFilterBuilder.java
index 5bea34e..68114e3 100644
--- a/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/MongoFilterBuilder.java
+++ b/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/MongoFilterBuilder.java
@@ -33,46 +33,35 @@ import org.slf4j.LoggerFactory;
public class MongoFilterBuilder extends
AbstractExprVisitor<Document, Void, RuntimeException> implements
DrillMongoConstants {
- private static final Logger logger = LoggerFactory
- .getLogger(MongoFilterBuilder.class);
- final MongoGroupScan groupScan;
- final LogicalExpression le;
+ private static final Logger logger = LoggerFactory.getLogger(MongoFilterBuilder.class);
+
+ private final LogicalExpression le;
private boolean allExpressionsConverted = true;
- public MongoFilterBuilder(MongoGroupScan groupScan,
- LogicalExpression conditionExp) {
- this.groupScan = groupScan;
+ public MongoFilterBuilder(LogicalExpression conditionExp) {
this.le = conditionExp;
}
public Document parseTree() {
- Document parsedSpec = le.accept(this, null);
- if (parsedSpec != null) {
- parsedSpec = mergeScanSpecs(FunctionNames.AND, null,
- parsedSpec);
- }
- return parsedSpec;
+ return le.accept(this, null);
}
- private Document mergeScanSpecs(String functionName,
- Document leftScanSpec, Document rightScanSpec) {
+ private Document mergeFilters(String functionName,
+ Document left, Document right) {
Document newFilter = new Document();
switch (functionName) {
case FunctionNames.AND:
- if (leftScanSpec != null
- && rightScanSpec != null) {
- newFilter = MongoUtils.andFilterAtIndex(leftScanSpec,
- rightScanSpec);
- } else if (leftScanSpec != null) {
- newFilter = leftScanSpec;
+ if (left != null && right != null) {
+ newFilter = MongoUtils.andFilterAtIndex(left, right);
+ } else if (left != null) {
+ newFilter = left;
} else {
- newFilter = rightScanSpec;
+ newFilter = right;
}
break;
case FunctionNames.OR:
- newFilter = MongoUtils.orFilterAtIndex(leftScanSpec,
- rightScanSpec);
+ newFilter = MongoUtils.orFilterAtIndex(left, right);
}
return newFilter;
}
@@ -91,18 +80,18 @@ public class MongoFilterBuilder extends
@Override
public Document visitBooleanOperator(BooleanOperator op, Void value) {
List<LogicalExpression> args = op.args();
- Document nodeScanSpec = null;
+ Document condition = null;
String functionName = op.getName();
for (LogicalExpression arg : args) {
switch (functionName) {
case FunctionNames.AND:
case FunctionNames.OR:
- if (nodeScanSpec == null) {
- nodeScanSpec = arg.accept(this, null);
+ if (condition == null) {
+ condition = arg.accept(this, null);
} else {
Document scanSpec = arg.accept(this, null);
if (scanSpec != null) {
- nodeScanSpec = mergeScanSpecs(functionName, nodeScanSpec, scanSpec);
+ condition = mergeFilters(functionName, condition, scanSpec);
} else {
allExpressionsConverted = false;
}
@@ -110,13 +99,13 @@ public class MongoFilterBuilder extends
break;
}
}
- return nodeScanSpec;
+ return condition;
}
@Override
public Document visitFunctionCall(FunctionCall call, Void value)
throws RuntimeException {
- Document nodeScanSpec = null;
+ Document functionCall = null;
String functionName = call.getName();
List<LogicalExpression> args = call.args();
@@ -125,7 +114,7 @@ public class MongoFilterBuilder extends
.process(call);
if (processor.isSuccess()) {
try {
- nodeScanSpec = createMongoScanSpec(processor.getFunctionName(),
+ functionCall = createFunctionCall(processor.getFunctionName(),
processor.getPath(), processor.getValue());
} catch (Exception e) {
logger.error(" Failed to creare Filter ", e);
@@ -136,29 +125,28 @@ public class MongoFilterBuilder extends
switch (functionName) {
case FunctionNames.AND:
case FunctionNames.OR:
- Document leftScanSpec = args.get(0).accept(this, null);
- Document rightScanSpec = args.get(1).accept(this, null);
- if (leftScanSpec != null && rightScanSpec != null) {
- nodeScanSpec = mergeScanSpecs(functionName, leftScanSpec,
- rightScanSpec);
+ Document left = args.get(0).accept(this, null);
+ Document right = args.get(1).accept(this, null);
+ if (left != null && right != null) {
+ functionCall = mergeFilters(functionName, left, right);
} else {
allExpressionsConverted = false;
if (FunctionNames.AND.equals(functionName)) {
- nodeScanSpec = leftScanSpec == null ? rightScanSpec : leftScanSpec;
+ functionCall = left == null ? right : left;
}
}
break;
}
}
- if (nodeScanSpec == null) {
+ if (functionCall == null) {
allExpressionsConverted = false;
}
- return nodeScanSpec;
+ return functionCall;
}
- private Document createMongoScanSpec(String functionName,
+ private Document createFunctionCall(String functionName,
SchemaPath field, Object fieldValue) {
// extract the field name
String fieldName = field.getRootSegmentPath();
diff --git a/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/MongoPushDownFilterForScan.java b/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/MongoPushDownFilterForScan.java
deleted file mode 100644
index 8dcd9d0..0000000
--- a/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/MongoPushDownFilterForScan.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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.
- */
-package org.apache.drill.exec.store.mongo;
-
-import java.io.IOException;
-import java.util.Collections;
-
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.core.Filter;
-import org.apache.drill.common.exceptions.DrillRuntimeException;
-import org.apache.drill.common.expression.LogicalExpression;
-import org.apache.drill.exec.planner.common.DrillScanRelBase;
-import org.apache.drill.exec.planner.logical.DrillOptiq;
-import org.apache.drill.exec.planner.logical.DrillParseContext;
-import org.apache.drill.exec.planner.logical.RelOptHelper;
-import org.apache.drill.exec.planner.physical.PrelUtil;
-import org.apache.drill.exec.store.StoragePluginOptimizerRule;
-import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.rex.RexNode;
-import org.bson.Document;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class MongoPushDownFilterForScan extends StoragePluginOptimizerRule {
- private static final Logger logger = LoggerFactory
- .getLogger(MongoPushDownFilterForScan.class);
- public static final StoragePluginOptimizerRule INSTANCE = new MongoPushDownFilterForScan();
-
- private MongoPushDownFilterForScan() {
- super(
- RelOptHelper.some(Filter.class, RelOptHelper.any(DrillScanRelBase.class)),
- "MongoPushDownFilterForScan");
- }
-
- @Override
- public void onMatch(RelOptRuleCall call) {
- final DrillScanRelBase scan = call.rel(1);
- final Filter filter = call.rel(0);
- final RexNode condition = filter.getCondition();
-
- MongoGroupScan groupScan = (MongoGroupScan) scan.getGroupScan();
-
- LogicalExpression conditionExp = DrillOptiq.toDrill(
- new DrillParseContext(PrelUtil.getPlannerSettings(call.getPlanner())), scan, condition);
- MongoFilterBuilder mongoFilterBuilder = new MongoFilterBuilder(groupScan,
- conditionExp);
- Document newScanSpec = mongoFilterBuilder.parseTree();
- if (newScanSpec == null) {
- return; // no filter pushdown so nothing to apply.
- }
-
- MongoGroupScan newGroupsScan;
- try {
- newGroupsScan = new MongoGroupScan(groupScan.getUserName(), groupScan.getStoragePlugin(),
- null, groupScan.getColumns(), groupScan.isUseAggregate());
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- throw new DrillRuntimeException(e.getMessage(), e);
- }
-
- RelNode newScanPrel = scan.copy(filter.getTraitSet(), newGroupsScan, filter.getRowType());
-
- if (mongoFilterBuilder.isAllExpressionsConverted()) {
- /*
- * Since we could convert the entire filter condition expression into an
- * Mongo filter, we can eliminate the filter operator altogether.
- */
- call.transformTo(newScanPrel);
- } else {
- call.transformTo(filter.copy(filter.getTraitSet(),
- Collections.singletonList(newScanPrel)));
- }
-
- }
-
- @Override
- public boolean matches(RelOptRuleCall call) {
- DrillScanRelBase scan = call.rel(1);
- return scan.getGroupScan() instanceof MongoGroupScan && super.matches(call);
- }
-}
diff --git a/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/plan/MongoPluginImplementor.java b/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/plan/MongoPluginImplementor.java
index d51447c..5561047 100644
--- a/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/plan/MongoPluginImplementor.java
+++ b/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/plan/MongoPluginImplementor.java
@@ -69,14 +69,11 @@ public class MongoPluginImplementor implements PluginImplementor {
visitChild(filter.getInput());
LogicalExpression conditionExp = DrillOptiq.toDrill(
- new DrillParseContext(PrelUtil.getPlannerSettings(filter.getCluster().getPlanner())), filter.getInput(), filter.getCondition());
- MongoFilterBuilder mongoFilterBuilder = new MongoFilterBuilder(groupScan, conditionExp);
+ new DrillParseContext(PrelUtil.getPlannerSettings(filter.getCluster().getPlanner())),
+ filter.getInput(),
+ filter.getCondition());
+ MongoFilterBuilder mongoFilterBuilder = new MongoFilterBuilder(conditionExp);
if (runAggregate) {
-// MongoRules.RexToMongoTranslator translator =
-// new MongoRules.RexToMongoTranslator(
-// (JavaTypeFactory) filter.getCluster().getTypeFactory(),
-// MongoRules.mongoFieldNames(filter.getInput().getRowType()));
-// Bson convertedFilterExpression = Aggregates.match(filter.getCondition().accept(translator).asDocument()).toBsonDocument();
Bson convertedFilterExpression = Aggregates.match(mongoFilterBuilder.parseTree()).toBsonDocument();
operations.add(convertedFilterExpression);
} else {
@@ -84,131 +81,6 @@ public class MongoPluginImplementor implements PluginImplementor {
}
}
-// private String translateMatch(RexNode condition) {
-// Map<String, Object> map = new HashMap<>();
-// map.put("$match", translateOr(condition));
-// return builder.toJsonString(map);
-// }
-//
-// private Object translateOr(RexNode condition) {
-// final RexNode condition2 =
-// RexUtil.expandSearch(rexBuilder, null, condition);
-//
-// List<Object> list = new ArrayList<>();
-// for (RexNode node : RelOptUtil.disjunctions(condition2)) {
-// list.add(translateAnd(node));
-// }
-// switch (list.size()) {
-// case 1:
-// return list.get(0);
-// default:
-// Map<String, Object> map = builder.map();
-// map.put("$or", list);
-// return map;
-// }
-// }
-//
-// /** Translates a condition that may be an AND of other conditions. Gathers
-// * together conditions that apply to the same field. */
-// private Map<String, Object> translateAnd(RexNode node0) {
-// eqMap.clear();
-// multimap.clear();
-// for (RexNode node : RelOptUtil.conjunctions(node0)) {
-// translateMatch2(node);
-// }
-// Map<String, Object> map = builder.map();
-// for (Map.Entry<String, RexLiteral> entry : eqMap.entrySet()) {
-// multimap.removeAll(entry.getKey());
-// map.put(entry.getKey(), literalValue(entry.getValue()));
-// }
-// for (Map.Entry<String, Collection<Pair<String, RexLiteral>>> entry
-// : multimap.asMap().entrySet()) {
-// Map<String, Object> map2 = builder.map();
-// for (Pair<String, RexLiteral> s : entry.getValue()) {
-// addPredicate(map2, s.left, literalValue(s.right));
-// }
-// map.put(entry.getKey(), map2);
-// }
-// return map;
-// }
-//
-// private Void translateMatch2(RexNode node) {
-// switch (node.getKind()) {
-// case EQUALS:
-// return translateBinary(null, null, (RexCall) node);
-// case LESS_THAN:
-// return translateBinary("$lt", "$gt", (RexCall) node);
-// case LESS_THAN_OR_EQUAL:
-// return translateBinary("$lte", "$gte", (RexCall) node);
-// case NOT_EQUALS:
-// return translateBinary("$ne", "$ne", (RexCall) node);
-// case GREATER_THAN:
-// return translateBinary("$gt", "$lt", (RexCall) node);
-// case GREATER_THAN_OR_EQUAL:
-// return translateBinary("$gte", "$lte", (RexCall) node);
-// default:
-// throw new AssertionError("cannot translate " + node);
-// }
-// }
-//
-// /** Translates a call to a binary operator, reversing arguments if
-// * necessary. */
-// private Void translateBinary(String op, String rop, RexCall call) {
-// final RexNode left = call.operands.get(0);
-// final RexNode right = call.operands.get(1);
-// boolean b = translateBinary2(op, left, right);
-// if (b) {
-// return null;
-// }
-// b = translateBinary2(rop, right, left);
-// if (b) {
-// return null;
-// }
-// throw new AssertionError("cannot translate op " + op + " call " + call);
-// }
-//
-// /** Translates a call to a binary operator. Returns whether successful. */
-// private boolean translateBinary2(String op, RexNode left, RexNode right) {
-// switch (right.getKind()) {
-// case LITERAL:
-// break;
-// default:
-// return false;
-// }
-// final RexLiteral rightLiteral = (RexLiteral) right;
-// switch (left.getKind()) {
-// case INPUT_REF:
-// final RexInputRef left1 = (RexInputRef) left;
-// String name = fieldNames.get(left1.getIndex());
-// translateOp2(op, name, rightLiteral);
-// return true;
-// case CAST:
-// return translateBinary2(op, ((RexCall) left).operands.get(0), right);
-// case ITEM:
-// String itemName = MongoRules.isItem((RexCall) left);
-// if (itemName != null) {
-// translateOp2(op, itemName, rightLiteral);
-// return true;
-// }
-// // fall through
-// default:
-// return false;
-// }
-// }
-//
-// private void translateOp2(String op, String name, RexLiteral right) {
-// if (op == null) {
-// // E.g.: {deptno: 100}
-// eqMap.put(name, right);
-// } else {
-// // E.g. {deptno: {$lt: 100}}
-// // which may later be combined with other conditions:
-// // E.g. {deptno: [$lt: 100, $gt: 50]}
-// multimap.put(name, Pair.of(op, right));
-// }
-// }
-
-
@Override
public void implement(PluginLimitRel limit) throws IOException {
runAggregate = true;
@@ -232,17 +104,17 @@ public class MongoPluginImplementor implements PluginImplementor {
visitChild(project.getInput());
if (runAggregate) {
- MongoRules.RexToMongoTranslator translator =
- new MongoRules.RexToMongoTranslator(
+ RexToMongoTranslator translator =
+ new RexToMongoTranslator(
(JavaTypeFactory) project.getCluster().getTypeFactory(),
- MongoRules.mongoFieldNames(project.getInput().getRowType()));
+ MongoAggregateUtils.mongoFieldNames(project.getInput().getRowType()));
List<BsonElement> items = new ArrayList<>();
for (Pair<RexNode, String> pair : project.getNamedProjects()) {
String name = pair.right;
BsonValue expr = pair.left.accept(translator);
items.add(expr.equals(new BsonString("$" + name))
- ? new BsonElement(MongoRules.maybeQuote(name), new BsonInt32(1))
- : new BsonElement(MongoRules.maybeQuote(name), expr));
+ ? new BsonElement(MongoAggregateUtils.maybeQuote(name), new BsonInt32(1))
+ : new BsonElement(MongoAggregateUtils.maybeQuote(name), expr));
}
BsonDocument projection = Aggregates.project(new BsonDocument(items)).toBsonDocument();
diff --git a/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/plan/MongoRules.java b/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/plan/MongoRules.java
deleted file mode 100644
index 953983b..0000000
--- a/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/plan/MongoRules.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * 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.
- */
-package org.apache.drill.exec.store.mongo.plan;
-
-import org.apache.calcite.adapter.enumerable.RexImpTable;
-import org.apache.calcite.adapter.enumerable.RexToLixTranslator;
-import org.apache.calcite.adapter.java.JavaTypeFactory;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rex.RexCall;
-import org.apache.calcite.rex.RexInputRef;
-import org.apache.calcite.rex.RexLiteral;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexVisitorImpl;
-import org.apache.calcite.sql.SqlKind;
-import org.apache.calcite.sql.SqlOperator;
-import org.apache.calcite.sql.fun.SqlStdOperatorTable;
-import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.calcite.sql.validate.SqlValidatorUtil;
-import org.apache.drill.exec.store.mongo.common.MongoOp;
-import org.bson.BsonArray;
-import org.bson.BsonDocument;
-import org.bson.BsonInt32;
-import org.bson.BsonNull;
-import org.bson.BsonString;
-import org.bson.BsonValue;
-
-import java.util.AbstractList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-public class MongoRules {
-
- /** Returns 'string' if it is a call to item['string'], null otherwise. */
- public static String isItem(RexCall call) {
- if (call.getOperator() != SqlStdOperatorTable.ITEM) {
- return null;
- }
- final RexNode op0 = call.operands.get(0);
- final RexNode op1 = call.operands.get(1);
- if (op0 instanceof RexInputRef
- && ((RexInputRef) op0).getIndex() == 0
- && op1 instanceof RexLiteral
- && ((RexLiteral) op1).getValue2() instanceof String) {
- return (String) ((RexLiteral) op1).getValue2();
- }
- return null;
- }
-
- static List<String> mongoFieldNames(final RelDataType rowType) {
- return SqlValidatorUtil.uniquify(
- new AbstractList<String>() {
- @Override public String get(int index) {
- final String name = rowType.getFieldList().get(index).getName();
- return name.startsWith("$") ? "_" + name.substring(2) : name;
- }
-
- @Override public int size() {
- return rowType.getFieldCount();
- }
- },
- SqlValidatorUtil.EXPR_SUGGESTER, true);
- }
-
- static String maybeQuote(String s) {
- if (!needsQuote(s)) {
- return s;
- }
- return quote(s);
- }
-
- static String quote(String s) {
- return "'" + s + "'"; // TODO: handle embedded quotes
- }
-
- private static boolean needsQuote(String s) {
- for (int i = 0, n = s.length(); i < n; i++) {
- char c = s.charAt(i);
- if (!Character.isJavaIdentifierPart(c)
- || c == '$') {
- return true;
- }
- }
- return false;
- }
-
- /** Translator from {@link RexNode} to strings in MongoDB's expression
- * language. */
- static class RexToMongoTranslator extends RexVisitorImpl<BsonValue> {
- private final JavaTypeFactory typeFactory;
- private final List<String> inFields;
-
- private static final Map<SqlOperator, String> MONGO_OPERATORS =
- new HashMap<>();
-
- static {
- MONGO_OPERATORS.put(SqlStdOperatorTable.DIVIDE, "$divide");
- MONGO_OPERATORS.put(SqlStdOperatorTable.MULTIPLY, "$multiply");
- MONGO_OPERATORS.put(SqlStdOperatorTable.ABS, "$abs");
- MONGO_OPERATORS.put(SqlStdOperatorTable.ACOS, "$acos");
- MONGO_OPERATORS.put(SqlStdOperatorTable.ASIN, "$asin");
- MONGO_OPERATORS.put(SqlStdOperatorTable.ATAN, "$atan");
- MONGO_OPERATORS.put(SqlStdOperatorTable.ATAN2, "$atan2");
- MONGO_OPERATORS.put(SqlStdOperatorTable.CEIL, "$ceil");
- MONGO_OPERATORS.put(SqlStdOperatorTable.CONCAT, "$concat");
- MONGO_OPERATORS.put(SqlStdOperatorTable.COS, "$cos");
- MONGO_OPERATORS.put(SqlStdOperatorTable.DAYOFMONTH, "$dayOfMonth");
- MONGO_OPERATORS.put(SqlStdOperatorTable.WEEK, "$isoWeek");
- MONGO_OPERATORS.put(SqlStdOperatorTable.YEAR, "$isoWeekYear");
- MONGO_OPERATORS.put(SqlStdOperatorTable.DAYOFWEEK, "$isoDayOfWeek");
- MONGO_OPERATORS.put(SqlStdOperatorTable.DAYOFYEAR, "$dayOfYear");
- MONGO_OPERATORS.put(SqlStdOperatorTable.RADIANS, "$degreesToRadians");
- MONGO_OPERATORS.put(SqlStdOperatorTable.DENSE_RANK, "$denseRank");
- MONGO_OPERATORS.put(SqlStdOperatorTable.EXP, "$exp");
- MONGO_OPERATORS.put(SqlStdOperatorTable.FLOOR, "$floor");
- MONGO_OPERATORS.put(SqlStdOperatorTable.HOUR, "$hour");
- MONGO_OPERATORS.put(SqlStdOperatorTable.LN, "$ln");
- MONGO_OPERATORS.put(SqlStdOperatorTable.LOG10, "$log10");
- MONGO_OPERATORS.put(SqlStdOperatorTable.MINUTE, "$minute");
- MONGO_OPERATORS.put(SqlStdOperatorTable.MOD, "$mod");
- MONGO_OPERATORS.put(SqlStdOperatorTable.MONTH, "$month");
- MONGO_OPERATORS.put(SqlStdOperatorTable.POWER, "$pow");
- MONGO_OPERATORS.put(SqlStdOperatorTable.DEGREES, "$radiansToDegrees");
- MONGO_OPERATORS.put(SqlStdOperatorTable.RAND, "$rand");
- MONGO_OPERATORS.put(SqlStdOperatorTable.REPLACE, "$replaceAll");
- MONGO_OPERATORS.put(SqlStdOperatorTable.ROUND, "$round");
- MONGO_OPERATORS.put(SqlStdOperatorTable.SECOND, "$second");
- MONGO_OPERATORS.put(SqlStdOperatorTable.SIN, "$sin");
- MONGO_OPERATORS.put(SqlStdOperatorTable.SQRT, "$sqrt");
- MONGO_OPERATORS.put(SqlStdOperatorTable.SUBSTRING, "$substr");
- MONGO_OPERATORS.put(SqlStdOperatorTable.PLUS, "$add");
- MONGO_OPERATORS.put(SqlStdOperatorTable.MINUS, "$subtract");
- MONGO_OPERATORS.put(SqlStdOperatorTable.TAN, "$tan");
- MONGO_OPERATORS.put(SqlStdOperatorTable.TRIM, "trim");
- MONGO_OPERATORS.put(SqlStdOperatorTable.TRUNCATE, "$trunc");
- // Boolean
- MONGO_OPERATORS.put(SqlStdOperatorTable.AND, MongoOp.AND.getCompareOp());
- MONGO_OPERATORS.put(SqlStdOperatorTable.OR, MongoOp.OR.getCompareOp());
- MONGO_OPERATORS.put(SqlStdOperatorTable.NOT, MongoOp.NOT.getCompareOp());
- // Comparison
- MONGO_OPERATORS.put(SqlStdOperatorTable.EQUALS, MongoOp.EQUAL.getCompareOp());
- MONGO_OPERATORS.put(SqlStdOperatorTable.NOT_EQUALS, MongoOp.NOT_EQUAL.getCompareOp());
- MONGO_OPERATORS.put(SqlStdOperatorTable.GREATER_THAN, MongoOp.GREATER.getCompareOp());
- MONGO_OPERATORS.put(SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, MongoOp.GREATER_OR_EQUAL.getCompareOp());
- MONGO_OPERATORS.put(SqlStdOperatorTable.LESS_THAN, MongoOp.LESS.getCompareOp());
- MONGO_OPERATORS.put(SqlStdOperatorTable.LESS_THAN_OR_EQUAL, MongoOp.LESS_OR_EQUAL.getCompareOp());
- }
-
- protected RexToMongoTranslator(JavaTypeFactory typeFactory,
- List<String> inFields) {
- super(true);
- this.typeFactory = typeFactory;
- this.inFields = inFields;
- }
-
- @Override
- public BsonValue visitLiteral(RexLiteral literal) {
- if (literal.getValue() == null) {
- return BsonNull.VALUE;
- }
- return new BsonDocument("$literal", new BsonString(
- RexToLixTranslator.translateLiteral(literal, literal.getType(),
- typeFactory, RexImpTable.NullAs.NOT_POSSIBLE).toString()));
- }
-
- @Override
- public BsonValue visitInputRef(RexInputRef inputRef) {
- return new BsonString(
- "$" + inFields.get(inputRef.getIndex()));
- }
-
- @Override
- public BsonValue visitCall(RexCall call) {
- String name = isItem(call);
- if (name != null) {
- return new BsonString("'$" + name + "'");
- }
- List<BsonValue> strings = call.operands.stream()
- .map(operand -> operand.accept(this))
- .collect(Collectors.toList());
-
- if (call.getKind() == SqlKind.CAST) {
- return strings.get(0);
- }
- String stdOperator = MONGO_OPERATORS.get(call.getOperator());
- if (stdOperator != null) {
- return new BsonDocument(stdOperator, new BsonArray(strings));
- }
- if (call.getOperator() == SqlStdOperatorTable.ITEM) {
- final RexNode op1 = call.operands.get(1);
- if (op1 instanceof RexLiteral
- && op1.getType().getSqlTypeName() == SqlTypeName.INTEGER) {
- return new BsonDocument("$arrayElemAt", new BsonArray(
- Arrays.asList(strings.get(0), new BsonInt32(((RexLiteral) op1).getValueAs(Integer.class)))));
- }
- }
- if (call.getOperator() == SqlStdOperatorTable.CASE) {
- StringBuilder sb = new StringBuilder();
- StringBuilder finish = new StringBuilder();
- // case(a, b, c) -> $cond:[a, b, c]
- // case(a, b, c, d) -> $cond:[a, b, $cond:[c, d, null]]
- // case(a, b, c, d, e) -> $cond:[a, b, $cond:[c, d, e]]
- for (int i = 0; i < strings.size(); i += 2) {
- sb.append("{$cond:[");
- finish.append("]}");
-
- sb.append(strings.get(i));
- sb.append(',');
- sb.append(strings.get(i + 1));
- sb.append(',');
- if (i == strings.size() - 3) {
- sb.append(strings.get(i + 2));
- break;
- }
- if (i == strings.size() - 2) {
- sb.append("null");
- break;
- }
- }
- sb.append(finish);
- return BsonDocument.parse(sb.toString());
- }
- throw new IllegalArgumentException("Translation of " + call
- + " is not supported by MongoProject");
- }
- }
-}
diff --git a/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/plan/RexToMongoTranslator.java b/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/plan/RexToMongoTranslator.java
new file mode 100644
index 0000000..478591f
--- /dev/null
+++ b/contrib/storage-mongo/src/main/java/org/apache/drill/exec/store/mongo/plan/RexToMongoTranslator.java
@@ -0,0 +1,184 @@
+package org.apache.drill.exec.store.mongo.plan;
+
+import org.apache.calcite.adapter.enumerable.RexImpTable;
+import org.apache.calcite.adapter.enumerable.RexToLixTranslator;
+import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexVisitorImpl;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.drill.exec.store.mongo.common.MongoOp;
+import org.bson.BsonArray;
+import org.bson.BsonDocument;
+import org.bson.BsonInt32;
+import org.bson.BsonNull;
+import org.bson.BsonString;
+import org.bson.BsonValue;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Translator from {@link RexNode} to strings in MongoDB's expression
+ * language.
+ */
+class RexToMongoTranslator extends RexVisitorImpl<BsonValue> {
+ private final JavaTypeFactory typeFactory;
+
+ private final List<String> inFields;
+
+ private static final Map<SqlOperator, String> MONGO_OPERATORS =
+ new HashMap<>();
+
+ static {
+ MONGO_OPERATORS.put(SqlStdOperatorTable.DIVIDE, "$divide");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.MULTIPLY, "$multiply");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.ABS, "$abs");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.ACOS, "$acos");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.ASIN, "$asin");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.ATAN, "$atan");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.ATAN2, "$atan2");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.CEIL, "$ceil");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.CONCAT, "$concat");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.COS, "$cos");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.DAYOFMONTH, "$dayOfMonth");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.WEEK, "$isoWeek");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.YEAR, "$isoWeekYear");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.DAYOFWEEK, "$isoDayOfWeek");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.DAYOFYEAR, "$dayOfYear");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.RADIANS, "$degreesToRadians");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.DENSE_RANK, "$denseRank");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.EXP, "$exp");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.FLOOR, "$floor");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.HOUR, "$hour");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.LN, "$ln");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.LOG10, "$log10");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.MINUTE, "$minute");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.MOD, "$mod");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.MONTH, "$month");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.POWER, "$pow");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.DEGREES, "$radiansToDegrees");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.RAND, "$rand");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.REPLACE, "$replaceAll");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.ROUND, "$round");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.SECOND, "$second");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.SIN, "$sin");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.SQRT, "$sqrt");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.SUBSTRING, "$substr");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.PLUS, "$add");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.MINUS, "$subtract");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.TAN, "$tan");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.TRIM, "trim");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.TRUNCATE, "$trunc");
+ MONGO_OPERATORS.put(SqlStdOperatorTable.AND, MongoOp.AND.getCompareOp());
+ MONGO_OPERATORS.put(SqlStdOperatorTable.OR, MongoOp.OR.getCompareOp());
+ MONGO_OPERATORS.put(SqlStdOperatorTable.NOT, MongoOp.NOT.getCompareOp());
+ MONGO_OPERATORS.put(SqlStdOperatorTable.EQUALS, MongoOp.EQUAL.getCompareOp());
+ MONGO_OPERATORS.put(SqlStdOperatorTable.NOT_EQUALS, MongoOp.NOT_EQUAL.getCompareOp());
+ MONGO_OPERATORS.put(SqlStdOperatorTable.GREATER_THAN, MongoOp.GREATER.getCompareOp());
+ MONGO_OPERATORS.put(SqlStdOperatorTable.GREATER_THAN_OR_EQUAL, MongoOp.GREATER_OR_EQUAL.getCompareOp());
+ MONGO_OPERATORS.put(SqlStdOperatorTable.LESS_THAN, MongoOp.LESS.getCompareOp());
+ MONGO_OPERATORS.put(SqlStdOperatorTable.LESS_THAN_OR_EQUAL, MongoOp.LESS_OR_EQUAL.getCompareOp());
+ }
+
+ protected RexToMongoTranslator(JavaTypeFactory typeFactory,
+ List<String> inFields) {
+ super(true);
+ this.typeFactory = typeFactory;
+ this.inFields = inFields;
+ }
+
+ @Override
+ public BsonValue visitLiteral(RexLiteral literal) {
+ if (literal.getValue() == null) {
+ return BsonNull.VALUE;
+ }
+ return new BsonDocument("$literal", new BsonString(
+ RexToLixTranslator.translateLiteral(literal, literal.getType(),
+ typeFactory, RexImpTable.NullAs.NOT_POSSIBLE).toString()));
+ }
+
+ @Override
+ public BsonValue visitInputRef(RexInputRef inputRef) {
+ return new BsonString("$" + inFields.get(inputRef.getIndex()));
+ }
+
+ @Override
+ public BsonValue visitCall(RexCall call) {
+ String name = isItem(call);
+ if (name != null) {
+ return new BsonString("'$" + name + "'");
+ }
+ List<BsonValue> strings = call.operands.stream()
+ .map(operand -> operand.accept(this))
+ .collect(Collectors.toList());
+
+ if (call.getKind() == SqlKind.CAST) {
+ return strings.get(0);
+ }
+ String stdOperator = MONGO_OPERATORS.get(call.getOperator());
+ if (stdOperator != null) {
+ return new BsonDocument(stdOperator, new BsonArray(strings));
+ }
+ if (call.getOperator() == SqlStdOperatorTable.ITEM) {
+ final RexNode op1 = call.operands.get(1);
+ if (op1 instanceof RexLiteral
+ && op1.getType().getSqlTypeName() == SqlTypeName.INTEGER) {
+ return new BsonDocument("$arrayElemAt", new BsonArray(
+ Arrays.asList(strings.get(0), new BsonInt32(((RexLiteral) op1).getValueAs(Integer.class)))));
+ }
+ }
+ if (call.getOperator() == SqlStdOperatorTable.CASE) {
+ // case(a, b, c) -> $cond:[a, b, c]
+ // case(a, b, c, d) -> $cond:[a, b, $cond:[c, d, null]]
+ // case(a, b, c, d, e) -> $cond:[a, b, $cond:[c, d, e]]
+ BsonDocument result = new BsonDocument();
+ BsonArray args = new BsonArray();
+ result.put("$cond", args);
+ for (int i = 0; i < strings.size(); i += 2) {
+ args.add(strings.get(i));
+ args.add(strings.get(i + 1));
+ if (i == strings.size() - 3) {
+ args.add(strings.get(i + 2));
+ break;
+ }
+ if (i == strings.size() - 2) {
+ args.add(BsonNull.VALUE);
+ break;
+ }
+ BsonArray innerArgs = new BsonArray();
+ args.add(innerArgs);
+ args = innerArgs;
+ }
+ return result;
+ }
+ throw new IllegalArgumentException("Translation of " + call + " is not supported by MongoProject");
+ }
+
+
+ /**
+ * Returns 'string' if it is a call to item['string'], null otherwise.
+ */
+ public static String isItem(RexCall call) {
+ if (call.getOperator() != SqlStdOperatorTable.ITEM) {
+ return null;
+ }
+ final RexNode op0 = call.operands.get(0);
+ final RexNode op1 = call.operands.get(1);
+ if (op0 instanceof RexInputRef
+ && ((RexInputRef) op0).getIndex() == 0
+ && op1 instanceof RexLiteral
+ && ((RexLiteral) op1).getValue2() instanceof String) {
+ return (String) ((RexLiteral) op1).getValue2();
+ }
+ return null;
+ }
+}