diff --git a/pom.xml b/pom.xml index 890b0ec..4dd02f6 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ UTF-8 4.12 3.1.0-incubating - 1.5.0 + 1.6.0 diff --git a/src/main/java/org/twilmes/sql/gremlin/processor/FieldMapVisitor.java b/src/main/java/org/twilmes/sql/gremlin/processor/FieldMapVisitor.java index 9d8425b..0b13044 100644 --- a/src/main/java/org/twilmes/sql/gremlin/processor/FieldMapVisitor.java +++ b/src/main/java/org/twilmes/sql/gremlin/processor/FieldMapVisitor.java @@ -19,6 +19,7 @@ package org.twilmes.sql.gremlin.processor; +import org.apache.calcite.adapter.enumerable.EnumerableCalc; import org.twilmes.sql.gremlin.rel.GremlinToEnumerableConverter; import org.apache.calcite.adapter.enumerable.EnumerableJoin; import org.apache.calcite.rel.RelNode; @@ -95,6 +96,20 @@ private GremlinToEnumerableConverter getConverter(int fieldIndex, String field, List fieldNames = join.getRowType().getFieldNames(); final String chosenField = fieldNames.get(fieldIndex); return fieldMap.get(join).get(chosenField); + } else if (node instanceof EnumerableCalc) { + final EnumerableCalc calc = (EnumerableCalc) node; + for (RelNode relNode : calc.getInputs()) { + if (relNode instanceof EnumerableJoin) { + return getConverter(fieldIndex, field, relNode); + } else { + try { + GremlinToEnumerableConverter converter = (GremlinToEnumerableConverter) relNode; + return converter; + } catch (ClassCastException e) { + + } + } + } } return null; } diff --git a/src/main/java/org/twilmes/sql/gremlin/processor/GremlinCompiler.java b/src/main/java/org/twilmes/sql/gremlin/processor/GremlinCompiler.java index 4bc1f4b..11ac45b 100644 --- a/src/main/java/org/twilmes/sql/gremlin/processor/GremlinCompiler.java +++ b/src/main/java/org/twilmes/sql/gremlin/processor/GremlinCompiler.java @@ -121,7 +121,7 @@ public List execute(String sql) { final FieldMapVisitor fieldMapper = new FieldMapVisitor(); new RelWalker(root, fieldMapper); final TraversalVisitor traversalVisitor = new TraversalVisitor(graph.traversal(), - scanMap, fieldMapper.getFieldMap()); + scanMap, fieldMapper.getFieldMap(), schemaConfig); new RelWalker(root, traversalVisitor); traversal = TraversalBuilder.buildMatch(graph.traversal(), traversalVisitor.getTableTraversalMap(), diff --git a/src/main/java/org/twilmes/sql/gremlin/processor/JoinQueryExecutor.java b/src/main/java/org/twilmes/sql/gremlin/processor/JoinQueryExecutor.java index 817a263..8e5040e 100644 --- a/src/main/java/org/twilmes/sql/gremlin/processor/JoinQueryExecutor.java +++ b/src/main/java/org/twilmes/sql/gremlin/processor/JoinQueryExecutor.java @@ -22,6 +22,7 @@ import org.twilmes.sql.gremlin.rel.GremlinToEnumerableConverter; import org.twilmes.sql.gremlin.rel.GremlinTraversalScan; import org.twilmes.sql.gremlin.rel.GremlinTraversalToEnumerableRelConverter; +import org.twilmes.sql.gremlin.schema.TableColumn; import org.twilmes.sql.gremlin.schema.TableDef; import org.twilmes.sql.gremlin.schema.TableUtil; import org.apache.calcite.adapter.enumerable.EnumerableInterpretable; @@ -153,8 +154,8 @@ public List run() { } private List project(Map fieldToTableMap, List fields, - List> results, - Map tableIdToTableDefMap) { + List> results, + Map tableIdToTableDefMap) { final List rows = new ArrayList<>(results.size()); Map labelTableIdMap = new HashMap<>(); for (Map.Entry entry : tableIdToTableDefMap.entrySet()) { @@ -185,8 +186,8 @@ private List project(Map fieldToTableMap, List f } } } - final Property property = result.get(tableId). - property(tableIdToTableDefMap.get(tableId).getColumn(simpleFieldName.toLowerCase()).getPropertyName()); + TableColumn tableColumn = tableIdToTableDefMap.get(tableId).getColumn(simpleFieldName.toLowerCase()); + final Property property = tableColumn == null ? Property.empty() : result.get(tableId).property(tableColumn.getPropertyName()); if(!(property instanceof EmptyProperty || property instanceof EmptyVertexProperty)) { if(result.get(tableId).label().equals(tableIdToTableDefMap.get(tableId).label)) { val = property.value(); diff --git a/src/main/java/org/twilmes/sql/gremlin/processor/TraversalVisitor.java b/src/main/java/org/twilmes/sql/gremlin/processor/TraversalVisitor.java index 4cf8592..9529b47 100644 --- a/src/main/java/org/twilmes/sql/gremlin/processor/TraversalVisitor.java +++ b/src/main/java/org/twilmes/sql/gremlin/processor/TraversalVisitor.java @@ -25,6 +25,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.twilmes.sql.gremlin.schema.SchemaConfig; import java.util.ArrayList; import java.util.HashMap; @@ -38,6 +39,7 @@ public class TraversalVisitor implements RelVisitor { private final Map> scanMap; private final Map> fieldMap; + private final SchemaConfig schemaConfig; // may use to check if join is valid private Integer id = 0; private Map tableIdMap = new HashMap<>(); private Map tableIdConverterMap = new HashMap<>(); @@ -50,9 +52,11 @@ public class TraversalVisitor implements RelVisitor { public TraversalVisitor(GraphTraversalSource traversalSource, Map> scanMap, - Map> fieldMap) { + Map> fieldMap, + SchemaConfig schemaConfig) { this.scanMap = scanMap; this.fieldMap = fieldMap; + this.schemaConfig = schemaConfig; } public List> getJoinPairs() { return joinPairs; } @@ -71,6 +75,9 @@ public void visit(RelNode node) { RelNode left = join.getLeft(); RelNode right = join.getRight(); + // TODO: should we check schema to see if the join is valid? + // found some cases the join happens to two tables that has no relationship + final Integer leftKeyId = join.getLeftKeys().get(0); final Integer rightKeyId = join.getRightKeys().get(0); @@ -82,7 +89,25 @@ public void visit(RelNode node) { final String rightAliasedColumn = rightJoinFields.get(rightKeyId); if(!(left instanceof GremlinToEnumerableConverter)) { - left = fieldMap.get(left).get(leftAliasedColumn); + if (fieldMap.get(left) != null && fieldMap.get(left).containsKey(leftAliasedColumn)) { + left = fieldMap.get(left).get(leftAliasedColumn); + } else { + Map leftMap = fieldMap.get(left); + if (leftMap == null) { + for(EnumerableJoin ej : fieldMap.keySet()) { + if (ej.getLeft().equals(left)) { + left = fieldMap.get(ej).get(leftAliasedColumn); + List scan = scanMap.get(left); + GraphTraversal leftTraversal = TraversalBuilder.toTraversal(scan); + traversals.add(leftTraversal); + tableTraversalMap.put(getTableId((GremlinToEnumerableConverter) left), leftTraversal); + break; + } + } + } else { + left = leftMap.get(leftAliasedColumn); + } + } } else { List scan = scanMap.get(left); GraphTraversal leftTraversal = TraversalBuilder.toTraversal(scan); @@ -90,7 +115,13 @@ public void visit(RelNode node) { tableTraversalMap.put(getTableId((GremlinToEnumerableConverter) left), leftTraversal); } if(!(right instanceof GremlinToEnumerableConverter)) { - right = fieldMap.get(join).get(rightAliasedColumn); + if (fieldMap.get(join) != null && fieldMap.get(join).containsKey(rightAliasedColumn)) { + right = fieldMap.get(join).get(rightAliasedColumn); + List scan = scanMap.get(right); + GraphTraversal rightTraversal = TraversalBuilder.toTraversal(scan); + traversals.add(rightTraversal); + tableTraversalMap.put(getTableId((GremlinToEnumerableConverter) right), rightTraversal); + } } else { List scan = scanMap.get(right); GraphTraversal rightTraversal = TraversalBuilder.toTraversal(scan); diff --git a/src/main/java/org/twilmes/sql/gremlin/rel/GremlinToEnumerableConverter.java b/src/main/java/org/twilmes/sql/gremlin/rel/GremlinToEnumerableConverter.java index 7d2c4bc..81383af 100644 --- a/src/main/java/org/twilmes/sql/gremlin/rel/GremlinToEnumerableConverter.java +++ b/src/main/java/org/twilmes/sql/gremlin/rel/GremlinToEnumerableConverter.java @@ -27,6 +27,7 @@ import org.apache.calcite.plan.*; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.convert.ConverterImpl; +import org.apache.calcite.rel.metadata.RelMetadataQuery; import java.util.List; @@ -50,8 +51,8 @@ public RelNode copy(RelTraitSet traitSet, List inputs) { } @Override - public RelOptCost computeSelfCost(RelOptPlanner planner) { - return super.computeSelfCost(planner).multiplyBy(.1); + public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) { + return super.computeSelfCost(planner, mq).multiplyBy(.1); } @Override diff --git a/src/main/java/org/twilmes/sql/gremlin/schema/TableUtil.java b/src/main/java/org/twilmes/sql/gremlin/schema/TableUtil.java index a8742fc..d637da9 100644 --- a/src/main/java/org/twilmes/sql/gremlin/schema/TableUtil.java +++ b/src/main/java/org/twilmes/sql/gremlin/schema/TableUtil.java @@ -61,11 +61,23 @@ public static Object convertType(Object value, TableColumn column) { case "string": return value; case "integer": - return ((Number) value).intValue(); + try { + return Integer.valueOf(String.valueOf(value)); + } catch ( NumberFormatException e ) { + return value; + } case "long": - return ((Number) value).longValue(); + try { + return Long.valueOf(String.valueOf(value)); + } catch ( NumberFormatException e ) { + return value; + } case "double": - return ((Number) value).doubleValue(); + try { + return Double.valueOf(String.valueOf(value)); + } catch ( NumberFormatException e ) { + return value; + } case "boolean": if(value instanceof Number) { if(value.equals(0)) {