http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraProject.java ---------------------------------------------------------------------- diff --git a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraProject.java b/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraProject.java deleted file mode 100644 index 5e55e46..0000000 --- a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraProject.java +++ /dev/null @@ -1,74 +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.calcite.adapter.cassandra; - -import org.apache.calcite.adapter.java.JavaTypeFactory; -import org.apache.calcite.plan.RelOptCluster; -import org.apache.calcite.plan.RelOptCost; -import org.apache.calcite.plan.RelOptPlanner; -import org.apache.calcite.plan.RelTraitSet; -import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.core.Project; -import org.apache.calcite.rel.metadata.RelMetadataQuery; -import org.apache.calcite.rel.type.RelDataType; -import org.apache.calcite.rex.RexNode; -import org.apache.calcite.util.Pair; - -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -/** - * Implementation of {@link org.apache.calcite.rel.core.Project} - * relational expression in Cassandra. - */ -public class CassandraProject extends Project implements CassandraRel { - public CassandraProject(RelOptCluster cluster, RelTraitSet traitSet, - RelNode input, List<? extends RexNode> projects, RelDataType rowType) { - super(cluster, traitSet, input, projects, rowType); - assert getConvention() == CassandraRel.CONVENTION; - assert getConvention() == input.getConvention(); - } - - @Override public Project copy(RelTraitSet traitSet, RelNode input, - List<RexNode> projects, RelDataType rowType) { - return new CassandraProject(getCluster(), traitSet, input, projects, - rowType); - } - - @Override public RelOptCost computeSelfCost(RelOptPlanner planner, - RelMetadataQuery mq) { - return super.computeSelfCost(planner, mq).multiplyBy(0.1); - } - - public void implement(Implementor implementor) { - implementor.visitChild(0, getInput()); - final CassandraRules.RexToCassandraTranslator translator = - new CassandraRules.RexToCassandraTranslator( - (JavaTypeFactory) getCluster().getTypeFactory(), - CassandraRules.cassandraFieldNames(getInput().getRowType())); - final Map<String, String> fields = new LinkedHashMap<String, String>(); - for (Pair<RexNode, String> pair : getNamedProjects()) { - final String name = pair.right; - final String originalName = pair.left.accept(translator); - fields.put(originalName, name); - } - implementor.add(fields, null); - } -} - -// End CassandraProject.java
http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraRel.java ---------------------------------------------------------------------- diff --git a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraRel.java b/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraRel.java deleted file mode 100644 index b74919d..0000000 --- a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraRel.java +++ /dev/null @@ -1,74 +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.calcite.adapter.cassandra; - -import org.apache.calcite.plan.Convention; -import org.apache.calcite.plan.RelOptTable; -import org.apache.calcite.rel.RelNode; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -/** - * Relational expression that uses Cassandra calling convention. - */ -public interface CassandraRel extends RelNode { - void implement(Implementor implementor); - - /** Calling convention for relational operations that occur in Cassandra. */ - Convention CONVENTION = new Convention.Impl("CASSANDRA", CassandraRel.class); - - /** Callback for the implementation process that converts a tree of - * {@link CassandraRel} nodes into a CQL query. */ - class Implementor { - final Map<String, String> selectFields = new LinkedHashMap<String, String>(); - final List<String> whereClause = new ArrayList<String>(); - int offset = 0; - int fetch = -1; - final List<String> order = new ArrayList<String>(); - - RelOptTable table; - CassandraTable cassandraTable; - - /** Adds newly projected fields and restricted predicates. - * - * @param fields New fields to be projected from a query - * @param predicates New predicates to be applied to the query - */ - public void add(Map<String, String> fields, List<String> predicates) { - if (fields != null) { - selectFields.putAll(fields); - } - if (predicates != null) { - whereClause.addAll(predicates); - } - } - - public void addOrder(List<String> newOrder) { - order.addAll(newOrder); - } - - public void visitChild(int ordinal, RelNode input) { - assert ordinal == 0; - ((CassandraRel) input).implement(this); - } - } -} - -// End CassandraRel.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraRules.java ---------------------------------------------------------------------- diff --git a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraRules.java b/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraRules.java deleted file mode 100644 index 3a9e9e9..0000000 --- a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraRules.java +++ /dev/null @@ -1,411 +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.calcite.adapter.cassandra; - -import org.apache.calcite.adapter.enumerable.EnumerableLimit; -import org.apache.calcite.adapter.java.JavaTypeFactory; -import org.apache.calcite.plan.Convention; -import org.apache.calcite.plan.RelOptRule; -import org.apache.calcite.plan.RelOptRuleCall; -import org.apache.calcite.plan.RelOptRuleOperand; -import org.apache.calcite.plan.RelOptUtil; -import org.apache.calcite.plan.RelTraitSet; -import org.apache.calcite.rel.RelCollation; -import org.apache.calcite.rel.RelCollations; -import org.apache.calcite.rel.RelFieldCollation; -import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.convert.ConverterRule; -import org.apache.calcite.rel.core.Sort; -import org.apache.calcite.rel.logical.LogicalFilter; -import org.apache.calcite.rel.logical.LogicalProject; -import org.apache.calcite.rel.type.RelDataType; -import org.apache.calcite.rex.RexCall; -import org.apache.calcite.rex.RexInputRef; -import org.apache.calcite.rex.RexNode; -import org.apache.calcite.rex.RexVisitorImpl; -import org.apache.calcite.runtime.PredicateImpl; -import org.apache.calcite.sql.SqlKind; -import org.apache.calcite.sql.validate.SqlValidatorUtil; -import org.apache.calcite.util.Pair; - -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * Rules and relational operators for - * {@link CassandraRel#CONVENTION} - * calling convention. - */ -public class CassandraRules { - private CassandraRules() {} - - public static final RelOptRule[] RULES = { - CassandraFilterRule.INSTANCE, - CassandraProjectRule.INSTANCE, - CassandraSortRule.INSTANCE, - CassandraLimitRule.INSTANCE - }; - - static List<String> cassandraFieldNames(final RelDataType rowType) { - return SqlValidatorUtil.uniquify(rowType.getFieldNames(), - SqlValidatorUtil.EXPR_SUGGESTER, true); - } - - /** Translator from {@link RexNode} to strings in Cassandra's expression - * language. */ - static class RexToCassandraTranslator extends RexVisitorImpl<String> { - private final JavaTypeFactory typeFactory; - private final List<String> inFields; - - protected RexToCassandraTranslator(JavaTypeFactory typeFactory, - List<String> inFields) { - super(true); - this.typeFactory = typeFactory; - this.inFields = inFields; - } - - @Override public String visitInputRef(RexInputRef inputRef) { - return inFields.get(inputRef.getIndex()); - } - } - - /** Base class for planner rules that convert a relational expression to - * Cassandra calling convention. */ - abstract static class CassandraConverterRule extends ConverterRule { - protected final Convention out; - - public CassandraConverterRule( - Class<? extends RelNode> clazz, - String description) { - this(clazz, Predicates.<RelNode>alwaysTrue(), description); - } - - public <R extends RelNode> CassandraConverterRule( - Class<R> clazz, - Predicate<? super R> predicate, - String description) { - super(clazz, predicate, Convention.NONE, CassandraRel.CONVENTION, description); - this.out = CassandraRel.CONVENTION; - } - } - - /** - * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalFilter} to a - * {@link CassandraFilter}. - */ - private static class CassandraFilterRule extends RelOptRule { - private static final Predicate<LogicalFilter> PREDICATE = - new PredicateImpl<LogicalFilter>() { - public boolean test(LogicalFilter input) { - // TODO: Check for an equality predicate on the partition key - // Right now this just checks if we have a single top-level AND - return RelOptUtil.disjunctions(input.getCondition()).size() == 1; - } - }; - - private static final CassandraFilterRule INSTANCE = new CassandraFilterRule(); - - private CassandraFilterRule() { - super(operand(LogicalFilter.class, operand(CassandraTableScan.class, none())), - "CassandraFilterRule"); - } - - @Override public boolean matches(RelOptRuleCall call) { - // Get the condition from the filter operation - LogicalFilter filter = call.rel(0); - RexNode condition = filter.getCondition(); - - // Get field names from the scan operation - CassandraTableScan scan = call.rel(1); - Pair<List<String>, List<String>> keyFields = scan.cassandraTable.getKeyFields(); - Set<String> partitionKeys = new HashSet<String>(keyFields.left); - List<String> fieldNames = CassandraRules.cassandraFieldNames(filter.getInput().getRowType()); - - List<RexNode> disjunctions = RelOptUtil.disjunctions(condition); - if (disjunctions.size() != 1) { - return false; - } else { - // Check that all conjunctions are primary key equalities - condition = disjunctions.get(0); - for (RexNode predicate : RelOptUtil.conjunctions(condition)) { - if (!isEqualityOnKey(predicate, fieldNames, partitionKeys, keyFields.right)) { - return false; - } - } - } - - // Either all of the partition keys must be specified or none - return partitionKeys.size() == keyFields.left.size() || partitionKeys.size() == 0; - } - - /** Check if the node is a supported predicate (primary key equality). - * - * @param node Condition node to check - * @param fieldNames Names of all columns in the table - * @param partitionKeys Names of primary key columns - * @param clusteringKeys Names of primary key columns - * @return True if the node represents an equality predicate on a primary key - */ - private boolean isEqualityOnKey(RexNode node, List<String> fieldNames, - Set<String> partitionKeys, List<String> clusteringKeys) { - if (node.getKind() != SqlKind.EQUALS) { - return false; - } - - RexCall call = (RexCall) node; - final RexNode left = call.operands.get(0); - final RexNode right = call.operands.get(1); - String key = compareFieldWithLiteral(left, right, fieldNames); - if (key == null) { - key = compareFieldWithLiteral(right, left, fieldNames); - } - if (key != null) { - return partitionKeys.remove(key) || clusteringKeys.contains(key); - } else { - return false; - } - } - - /** Check if an equality operation is comparing a primary key column with a literal. - * - * @param left Left operand of the equality - * @param right Right operand of the equality - * @param fieldNames Names of all columns in the table - * @return The field being compared or null if there is no key equality - */ - private String compareFieldWithLiteral(RexNode left, RexNode right, List<String> fieldNames) { - // FIXME Ignore casts for new and assume they aren't really necessary - if (left.isA(SqlKind.CAST)) { - left = ((RexCall) left).getOperands().get(0); - } - - if (left.isA(SqlKind.INPUT_REF) && right.isA(SqlKind.LITERAL)) { - final RexInputRef left1 = (RexInputRef) left; - String name = fieldNames.get(left1.getIndex()); - return name; - } else { - return null; - } - } - - /** @see org.apache.calcite.rel.convert.ConverterRule */ - public void onMatch(RelOptRuleCall call) { - LogicalFilter filter = call.rel(0); - CassandraTableScan scan = call.rel(1); - if (filter.getTraitSet().contains(Convention.NONE)) { - final RelNode converted = convert(filter, scan); - if (converted != null) { - call.transformTo(converted); - } - } - } - - public RelNode convert(LogicalFilter filter, CassandraTableScan scan) { - final RelTraitSet traitSet = filter.getTraitSet().replace(CassandraRel.CONVENTION); - final Pair<List<String>, List<String>> keyFields = scan.cassandraTable.getKeyFields(); - return new CassandraFilter( - filter.getCluster(), - traitSet, - convert(filter.getInput(), CassandraRel.CONVENTION), - filter.getCondition(), - keyFields.left, - keyFields.right, - scan.cassandraTable.getClusteringOrder()); - } - } - - /** - * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalProject} - * to a {@link CassandraProject}. - */ - private static class CassandraProjectRule extends CassandraConverterRule { - private static final CassandraProjectRule INSTANCE = new CassandraProjectRule(); - - private CassandraProjectRule() { - super(LogicalProject.class, "CassandraProjectRule"); - } - - @Override public boolean matches(RelOptRuleCall call) { - LogicalProject project = call.rel(0); - for (RexNode e : project.getProjects()) { - if (!(e instanceof RexInputRef)) { - return false; - } - } - - return true; - } - - public RelNode convert(RelNode rel) { - final LogicalProject project = (LogicalProject) rel; - final RelTraitSet traitSet = project.getTraitSet().replace(out); - return new CassandraProject(project.getCluster(), traitSet, - convert(project.getInput(), out), project.getProjects(), - project.getRowType()); - } - } - - /** - * Rule to convert a {@link org.apache.calcite.rel.core.Sort} to a - * {@link CassandraSort}. - */ - private static class CassandraSortRule extends RelOptRule { - private static final Predicate<Sort> SORT_PREDICATE = - new PredicateImpl<Sort>() { - public boolean test(Sort input) { - // Limits are handled by CassandraLimit - return input.offset == null && input.fetch == null; - } - }; - private static final Predicate<CassandraFilter> FILTER_PREDICATE = - new PredicateImpl<CassandraFilter>() { - public boolean test(CassandraFilter input) { - // We can only use implicit sorting within a single partition - return input.isSinglePartition(); - } - }; - private static final RelOptRuleOperand CASSANDRA_OP = - operand(CassandraToEnumerableConverter.class, - operand(CassandraFilter.class, null, FILTER_PREDICATE, any())); - - private static final CassandraSortRule INSTANCE = new CassandraSortRule(); - - private CassandraSortRule() { - super(operand(Sort.class, null, SORT_PREDICATE, CASSANDRA_OP), "CassandraSortRule"); - } - - public RelNode convert(Sort sort, CassandraFilter filter) { - final RelTraitSet traitSet = - sort.getTraitSet().replace(CassandraRel.CONVENTION) - .replace(sort.getCollation()); - return new CassandraSort(sort.getCluster(), traitSet, - convert(sort.getInput(), traitSet.replace(RelCollations.EMPTY)), - sort.getCollation()); - } - - public boolean matches(RelOptRuleCall call) { - final Sort sort = call.rel(0); - final CassandraFilter filter = call.rel(2); - return collationsCompatible(sort.getCollation(), filter.getImplicitCollation()); - } - - /** Check if it is possible to exploit native CQL sorting for a given collation. - * - * @return True if it is possible to achieve this sort in Cassandra - */ - private boolean collationsCompatible(RelCollation sortCollation, - RelCollation implicitCollation) { - List<RelFieldCollation> sortFieldCollations = sortCollation.getFieldCollations(); - List<RelFieldCollation> implicitFieldCollations = implicitCollation.getFieldCollations(); - - if (sortFieldCollations.size() > implicitFieldCollations.size()) { - return false; - } - if (sortFieldCollations.size() == 0) { - return true; - } - - // Check if we need to reverse the order of the implicit collation - boolean reversed = reverseDirection(sortFieldCollations.get(0).getDirection()) - == implicitFieldCollations.get(0).getDirection(); - - for (int i = 0; i < sortFieldCollations.size(); i++) { - RelFieldCollation sorted = sortFieldCollations.get(i); - RelFieldCollation implied = implicitFieldCollations.get(i); - - // Check that the fields being sorted match - if (sorted.getFieldIndex() != implied.getFieldIndex()) { - return false; - } - - // Either all fields must be sorted in the same direction - // or the opposite direction based on whether we decided - // if the sort direction should be reversed above - RelFieldCollation.Direction sortDirection = sorted.getDirection(); - RelFieldCollation.Direction implicitDirection = implied.getDirection(); - if ((!reversed && sortDirection != implicitDirection) - || (reversed && reverseDirection(sortDirection) != implicitDirection)) { - return false; - } - } - - return true; - } - - /** Find the reverse of a given collation direction. - * - * @return Reverse of the input direction - */ - private RelFieldCollation.Direction reverseDirection(RelFieldCollation.Direction direction) { - switch(direction) { - case ASCENDING: - case STRICTLY_ASCENDING: - return RelFieldCollation.Direction.DESCENDING; - case DESCENDING: - case STRICTLY_DESCENDING: - return RelFieldCollation.Direction.ASCENDING; - default: - return null; - } - } - - /** @see org.apache.calcite.rel.convert.ConverterRule */ - public void onMatch(RelOptRuleCall call) { - final Sort sort = call.rel(0); - CassandraFilter filter = call.rel(2); - final RelNode converted = convert(sort, filter); - if (converted != null) { - call.transformTo(converted); - } - } - } - - /** - * Rule to convert a {@link org.apache.calcite.adapter.enumerable.EnumerableLimit} to a - * {@link CassandraLimit}. - */ - private static class CassandraLimitRule extends RelOptRule { - private static final CassandraLimitRule INSTANCE = new CassandraLimitRule(); - - private CassandraLimitRule() { - super(operand(EnumerableLimit.class, operand(CassandraToEnumerableConverter.class, any())), - "CassandraLimitRule"); - } - - public RelNode convert(EnumerableLimit limit) { - final RelTraitSet traitSet = - limit.getTraitSet().replace(CassandraRel.CONVENTION); - return new CassandraLimit(limit.getCluster(), traitSet, - convert(limit.getInput(), CassandraRel.CONVENTION), limit.offset, limit.fetch); - } - - /** @see org.apache.calcite.rel.convert.ConverterRule */ - public void onMatch(RelOptRuleCall call) { - final EnumerableLimit limit = call.rel(0); - final RelNode converted = convert(limit); - if (converted != null) { - call.transformTo(converted); - } - } - } -} - -// End CassandraRules.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraSchema.java ---------------------------------------------------------------------- diff --git a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraSchema.java b/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraSchema.java deleted file mode 100644 index 21f37be..0000000 --- a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraSchema.java +++ /dev/null @@ -1,305 +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.calcite.adapter.cassandra; - -import org.apache.calcite.avatica.util.Casing; -import org.apache.calcite.jdbc.CalciteSchema; -import org.apache.calcite.rel.RelFieldCollation; -import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.type.RelDataTypeFactory; -import org.apache.calcite.rel.type.RelDataTypeImpl; -import org.apache.calcite.rel.type.RelDataTypeSystem; -import org.apache.calcite.rel.type.RelProtoDataType; -import org.apache.calcite.runtime.Hook; -import org.apache.calcite.schema.SchemaPlus; -import org.apache.calcite.schema.Table; -import org.apache.calcite.schema.impl.AbstractSchema; -import org.apache.calcite.schema.impl.MaterializedViewTable; -import org.apache.calcite.sql.SqlDialect; -import org.apache.calcite.sql.SqlSelect; -import org.apache.calcite.sql.SqlWriter; -import org.apache.calcite.sql.parser.SqlParseException; -import org.apache.calcite.sql.parser.SqlParser; -import org.apache.calcite.sql.pretty.SqlPrettyWriter; -import org.apache.calcite.sql.type.SqlTypeFactoryImpl; -import org.apache.calcite.sql.type.SqlTypeName; -import org.apache.calcite.util.Pair; -import org.apache.calcite.util.Util; -import org.apache.calcite.util.trace.CalciteTrace; - -import com.datastax.driver.core.AbstractTableMetadata; -import com.datastax.driver.core.Cluster; -import com.datastax.driver.core.ClusteringOrder; -import com.datastax.driver.core.ColumnMetadata; -import com.datastax.driver.core.DataType; -import com.datastax.driver.core.KeyspaceMetadata; -import com.datastax.driver.core.MaterializedViewMetadata; -import com.datastax.driver.core.Session; -import com.datastax.driver.core.TableMetadata; -import com.google.common.base.Function; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; - -import org.slf4j.Logger; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * Schema mapped onto a Cassandra column family - */ -public class CassandraSchema extends AbstractSchema { - final Session session; - final String keyspace; - private final SchemaPlus parentSchema; - final String name; - final Hook.Closeable hook; - - protected static final Logger LOGGER = CalciteTrace.getPlannerTracer(); - - /** - * Creates a Cassandra schema. - * - * @param host Cassandra host, e.g. "localhost" - * @param keyspace Cassandra keyspace name, e.g. "twissandra" - */ - public CassandraSchema(String host, String keyspace, SchemaPlus parentSchema, String name) { - this(host, keyspace, null, null, parentSchema, name); - } - - /** - * Creates a Cassandra schema. - * - * @param host Cassandra host, e.g. "localhost" - * @param keyspace Cassandra keyspace name, e.g. "twissandra" - * @param username Cassandra username - * @param password Cassandra password - */ - public CassandraSchema(String host, String keyspace, String username, String password, - SchemaPlus parentSchema, String name) { - super(); - - this.keyspace = keyspace; - try { - Cluster cluster; - if (username != null && password != null) { - cluster = Cluster.builder().addContactPoint(host) - .withCredentials(username, password).build(); - } else { - cluster = Cluster.builder().addContactPoint(host).build(); - } - - this.session = cluster.connect(keyspace); - } catch (Exception e) { - throw new RuntimeException(e); - } - this.parentSchema = parentSchema; - this.name = name; - - this.hook = Hook.TRIMMED.add(new Function<RelNode, Void>() { - public Void apply(RelNode node) { - CassandraSchema.this.addMaterializedViews(); - return null; - } - }); - } - - RelProtoDataType getRelDataType(String columnFamily, boolean view) { - List<ColumnMetadata> columns; - if (view) { - columns = getKeyspace().getMaterializedView(columnFamily).getColumns(); - } else { - columns = getKeyspace().getTable(columnFamily).getColumns(); - } - - // Temporary type factory, just for the duration of this method. Allowable - // because we're creating a proto-type, not a type; before being used, the - // proto-type will be copied into a real type factory. - final RelDataTypeFactory typeFactory = - new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT); - final RelDataTypeFactory.FieldInfoBuilder fieldInfo = typeFactory.builder(); - for (ColumnMetadata column : columns) { - final String columnName = column.getName(); - final DataType type = column.getType(); - - // TODO: This mapping of types can be done much better - SqlTypeName typeName = SqlTypeName.ANY; - if (type == DataType.uuid() || type == DataType.timeuuid()) { - // We currently rely on this in CassandraFilter to detect UUID columns. - // That is, these fixed length literals should be unquoted in CQL. - typeName = SqlTypeName.CHAR; - } else if (type == DataType.ascii() || type == DataType.text() - || type == DataType.varchar()) { - typeName = SqlTypeName.VARCHAR; - } else if (type == DataType.cint() || type == DataType.varint()) { - typeName = SqlTypeName.INTEGER; - } else if (type == DataType.bigint()) { - typeName = SqlTypeName.BIGINT; - } else if (type == DataType.cdouble() || type == DataType.cfloat() - || type == DataType.decimal()) { - typeName = SqlTypeName.DOUBLE; - } - - fieldInfo.add(columnName, typeFactory.createSqlType(typeName)).nullable(true); - } - - return RelDataTypeImpl.proto(fieldInfo.build()); - } - - /** - * Get all primary key columns from the underlying CQL table - * - * @return A list of field names that are part of the partition and clustering keys - */ - Pair<List<String>, List<String>> getKeyFields(String columnFamily, boolean view) { - AbstractTableMetadata table; - if (view) { - table = getKeyspace().getMaterializedView(columnFamily); - } else { - table = getKeyspace().getTable(columnFamily); - } - - List<ColumnMetadata> partitionKey = table.getPartitionKey(); - List<String> pKeyFields = new ArrayList<String>(); - for (ColumnMetadata column : partitionKey) { - pKeyFields.add(column.getName()); - } - - List<ColumnMetadata> clusteringKey = table.getClusteringColumns(); - List<String> cKeyFields = new ArrayList<String>(); - for (ColumnMetadata column : clusteringKey) { - cKeyFields.add(column.getName()); - } - - return Pair.of((List<String>) ImmutableList.copyOf(pKeyFields), - (List<String>) ImmutableList.copyOf(cKeyFields)); - } - - /** Get the collation of all clustering key columns. - * - * @return A RelCollations representing the collation of all clustering keys - */ - public List<RelFieldCollation> getClusteringOrder(String columnFamily, boolean view) { - AbstractTableMetadata table; - if (view) { - table = getKeyspace().getMaterializedView(columnFamily); - } else { - table = getKeyspace().getTable(columnFamily); - } - - List<ClusteringOrder> clusteringOrder = table.getClusteringOrder(); - List<RelFieldCollation> keyCollations = new ArrayList<RelFieldCollation>(); - - int i = 0; - for (ClusteringOrder order : clusteringOrder) { - RelFieldCollation.Direction direction; - switch(order) { - case DESC: - direction = RelFieldCollation.Direction.DESCENDING; - break; - case ASC: - default: - direction = RelFieldCollation.Direction.ASCENDING; - break; - } - keyCollations.add(new RelFieldCollation(i, direction)); - i++; - } - - return keyCollations; - } - - /** Add all materialized views defined in the schema to this column family - */ - private void addMaterializedViews() { - // Close the hook use to get us here - hook.close(); - - for (MaterializedViewMetadata view : getKeyspace().getMaterializedViews()) { - String tableName = view.getBaseTable().getName(); - StringBuilder queryBuilder = new StringBuilder("SELECT "); - - // Add all the selected columns to the query - List<String> columnNames = new ArrayList<String>(); - for (ColumnMetadata column : view.getColumns()) { - columnNames.add("\"" + column.getName() + "\""); - } - queryBuilder.append(Util.toString(columnNames, "", ", ", "")); - - queryBuilder.append(" FROM \"" + tableName + "\""); - - // Get the where clause from the system schema - String whereQuery = "SELECT where_clause from system_schema.views " - + "WHERE keyspace_name='" + keyspace + "' AND view_name='" + view.getName() + "'"; - queryBuilder.append(" WHERE " + session.execute(whereQuery).one().getString(0)); - - // Parse and unparse the view query to get properly quoted field names - String query = queryBuilder.toString(); - SqlParser.ConfigBuilder configBuilder = SqlParser.configBuilder(); - configBuilder.setUnquotedCasing(Casing.UNCHANGED); - - SqlSelect parsedQuery; - try { - parsedQuery = (SqlSelect) SqlParser.create(query, configBuilder.build()).parseQuery(); - } catch (SqlParseException e) { - LOGGER.warn("Could not parse query {} for CQL view {}.{}", - query, keyspace, view.getName()); - continue; - } - - StringWriter stringWriter = new StringWriter(query.length()); - PrintWriter printWriter = new PrintWriter(stringWriter); - SqlWriter writer = new SqlPrettyWriter(SqlDialect.CALCITE, true, printWriter); - parsedQuery.unparse(writer, 0, 0); - query = stringWriter.toString(); - - // Add the view for this query - String viewName = "$" + getTableNames().size(); - SchemaPlus schema = parentSchema.getSubSchema(name); - CalciteSchema calciteSchema = CalciteSchema.from(schema); - - List<String> viewPath = calciteSchema.path(viewName); - - schema.add(viewName, - MaterializedViewTable.create(calciteSchema, query, - null, viewPath, view.getName(), true)); - } - } - - @Override protected Map<String, Table> getTableMap() { - final ImmutableMap.Builder<String, Table> builder = ImmutableMap.builder(); - for (TableMetadata table : getKeyspace().getTables()) { - String tableName = table.getName(); - builder.put(tableName, new CassandraTable(this, tableName)); - - for (MaterializedViewMetadata view : table.getViews()) { - String viewName = view.getName(); - builder.put(viewName, new CassandraTable(this, viewName, true)); - } - } - return builder.build(); - } - - private KeyspaceMetadata getKeyspace() { - return session.getCluster().getMetadata().getKeyspace(keyspace); - } -} - -// End CassandraSchema.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraSchemaFactory.java ---------------------------------------------------------------------- diff --git a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraSchemaFactory.java b/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraSchemaFactory.java deleted file mode 100644 index 136b81b..0000000 --- a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraSchemaFactory.java +++ /dev/null @@ -1,44 +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.calcite.adapter.cassandra; - -import org.apache.calcite.schema.Schema; -import org.apache.calcite.schema.SchemaFactory; -import org.apache.calcite.schema.SchemaPlus; - -import java.util.Map; - -/** - * Factory that creates a {@link CassandraSchema} - */ -@SuppressWarnings("UnusedDeclaration") -public class CassandraSchemaFactory implements SchemaFactory { - public CassandraSchemaFactory() { - } - - public Schema create(SchemaPlus parentSchema, String name, - Map<String, Object> operand) { - Map map = (Map) operand; - String host = (String) map.get("host"); - String keyspace = (String) map.get("keyspace"); - String username = (String) map.get("username"); - String password = (String) map.get("password"); - return new CassandraSchema(host, keyspace, username, password, parentSchema, name); - } -} - -// End CassandraSchemaFactory.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraSort.java ---------------------------------------------------------------------- diff --git a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraSort.java b/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraSort.java deleted file mode 100644 index 8487815..0000000 --- a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraSort.java +++ /dev/null @@ -1,85 +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.calcite.adapter.cassandra; - -import org.apache.calcite.plan.RelOptCluster; -import org.apache.calcite.plan.RelOptCost; -import org.apache.calcite.plan.RelOptPlanner; -import org.apache.calcite.plan.RelTraitSet; -import org.apache.calcite.rel.RelCollation; -import org.apache.calcite.rel.RelFieldCollation; -import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.core.Sort; -import org.apache.calcite.rel.metadata.RelMetadataQuery; -import org.apache.calcite.rel.type.RelDataTypeField; -import org.apache.calcite.rex.RexNode; - -import java.util.ArrayList; -import java.util.List; - -/** - * Implementation of {@link org.apache.calcite.rel.core.Sort} - * relational expression in Cassandra. - */ -public class CassandraSort extends Sort implements CassandraRel { - public CassandraSort(RelOptCluster cluster, RelTraitSet traitSet, - RelNode child, RelCollation collation) { - super(cluster, traitSet, child, collation, null, null); - - assert getConvention() == CassandraRel.CONVENTION; - assert getConvention() == child.getConvention(); - } - - @Override public RelOptCost computeSelfCost(RelOptPlanner planner, - RelMetadataQuery mq) { - RelOptCost cost = super.computeSelfCost(planner, mq); - if (!collation.getFieldCollations().isEmpty()) { - return cost.multiplyBy(0.05); - } else { - return cost; - } - } - - @Override public Sort copy(RelTraitSet traitSet, RelNode input, - RelCollation newCollation, RexNode offset, RexNode fetch) { - return new CassandraSort(getCluster(), traitSet, input, collation); - } - - public void implement(Implementor implementor) { - implementor.visitChild(0, getInput()); - - List<RelFieldCollation> sortCollations = collation.getFieldCollations(); - List<String> fieldOrder = new ArrayList<String>(); - if (!sortCollations.isEmpty()) { - // Construct a series of order clauses from the desired collation - final List<RelDataTypeField> fields = getRowType().getFieldList(); - for (RelFieldCollation fieldCollation : sortCollations) { - final String name = - fields.get(fieldCollation.getFieldIndex()).getName(); - String direction = "ASC"; - if (fieldCollation.getDirection().equals(RelFieldCollation.Direction.DESCENDING)) { - direction = "DESC"; - } - fieldOrder.add(name + " " + direction); - } - - implementor.addOrder(fieldOrder); - } - } -} - -// End CassandraSort.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraTable.java ---------------------------------------------------------------------- diff --git a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraTable.java b/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraTable.java deleted file mode 100644 index ec2a636..0000000 --- a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraTable.java +++ /dev/null @@ -1,256 +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.calcite.adapter.cassandra; - -import org.apache.calcite.adapter.java.AbstractQueryableTable; -import org.apache.calcite.linq4j.AbstractEnumerable; -import org.apache.calcite.linq4j.Enumerable; -import org.apache.calcite.linq4j.Enumerator; -import org.apache.calcite.linq4j.QueryProvider; -import org.apache.calcite.linq4j.Queryable; -import org.apache.calcite.linq4j.function.Function1; -import org.apache.calcite.plan.RelOptCluster; -import org.apache.calcite.plan.RelOptTable; -import org.apache.calcite.rel.RelFieldCollation; -import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.type.RelDataType; -import org.apache.calcite.rel.type.RelDataTypeFactory; -import org.apache.calcite.rel.type.RelDataTypeImpl; -import org.apache.calcite.rel.type.RelDataTypeSystem; -import org.apache.calcite.rel.type.RelProtoDataType; -import org.apache.calcite.schema.SchemaPlus; -import org.apache.calcite.schema.TranslatableTable; -import org.apache.calcite.schema.impl.AbstractTableQueryable; -import org.apache.calcite.sql.type.SqlTypeFactoryImpl; -import org.apache.calcite.sql.type.SqlTypeName; -import org.apache.calcite.util.Pair; -import org.apache.calcite.util.Util; - -import com.datastax.driver.core.ResultSet; -import com.datastax.driver.core.Session; - -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * Table based on a Cassandra column family - */ -public class CassandraTable extends AbstractQueryableTable - implements TranslatableTable { - RelProtoDataType protoRowType; - Pair<List<String>, List<String>> keyFields; - List<RelFieldCollation> clusteringOrder; - private final CassandraSchema schema; - private final String columnFamily; - private final boolean view; - - public CassandraTable(CassandraSchema schema, String columnFamily, boolean view) { - super(Object[].class); - this.schema = schema; - this.columnFamily = columnFamily; - this.view = view; - } - - public CassandraTable(CassandraSchema schema, String columnFamily) { - this(schema, columnFamily, false); - } - - public String toString() { - return "CassandraTable {" + columnFamily + "}"; - } - - public RelDataType getRowType(RelDataTypeFactory typeFactory) { - if (protoRowType == null) { - protoRowType = schema.getRelDataType(columnFamily, view); - } - return protoRowType.apply(typeFactory); - } - - public Pair<List<String>, List<String>> getKeyFields() { - if (keyFields == null) { - keyFields = schema.getKeyFields(columnFamily, view); - } - return keyFields; - } - - public List<RelFieldCollation> getClusteringOrder() { - if (clusteringOrder == null) { - clusteringOrder = schema.getClusteringOrder(columnFamily, view); - } - return clusteringOrder; - } - - public Enumerable<Object> query(final Session session) { - return query(session, Collections.<Map.Entry<String, Class>>emptyList(), - Collections.<Map.Entry<String, String>>emptyList(), - Collections.<String>emptyList(), Collections.<String>emptyList(), 0, -1); - } - - /** Executes a CQL query on the underlying table. - * - * @param session Cassandra session - * @param fields List of fields to project - * @param predicates A list of predicates which should be used in the query - * @return Enumerator of results - */ - public Enumerable<Object> query(final Session session, List<Map.Entry<String, Class>> fields, - final List<Map.Entry<String, String>> selectFields, List<String> predicates, - List<String> order, final Integer offset, final Integer fetch) { - // Build the type of the resulting row based on the provided fields - final RelDataTypeFactory typeFactory = - new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT); - final RelDataTypeFactory.FieldInfoBuilder fieldInfo = typeFactory.builder(); - final RelDataType rowType = protoRowType.apply(typeFactory); - - Function1<String, Void> addField = new Function1<String, Void>() { - public Void apply(String fieldName) { - SqlTypeName typeName = rowType.getField(fieldName, true, false).getType().getSqlTypeName(); - fieldInfo.add(fieldName, typeFactory.createSqlType(typeName)).nullable(true); - return null; - } - }; - - if (selectFields.isEmpty()) { - for (Map.Entry<String, Class> field : fields) { - addField.apply(field.getKey()); - } - } else { - for (Map.Entry<String, String> field : selectFields) { - addField.apply(field.getKey()); - } - } - - final RelProtoDataType resultRowType = RelDataTypeImpl.proto(fieldInfo.build()); - - // Construct the list of fields to project - final String selectString; - if (selectFields.isEmpty()) { - selectString = "*"; - } else { - selectString = Util.toString(new Iterable<String>() { - public Iterator<String> iterator() { - final Iterator<Map.Entry<String, String>> selectIterator = - selectFields.iterator(); - - return new Iterator<String>() { - @Override public boolean hasNext() { - return selectIterator.hasNext(); - } - - @Override public String next() { - Map.Entry<String, String> entry = selectIterator.next(); - return entry.getKey() + " AS " + entry.getValue(); - } - - @Override public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - }, "", ", ", ""); - } - - // Combine all predicates conjunctively - String whereClause = ""; - if (!predicates.isEmpty()) { - whereClause = " WHERE "; - whereClause += Util.toString(predicates, "", " AND ", ""); - } - - // Build and issue the query and return an Enumerator over the results - StringBuilder queryBuilder = new StringBuilder("SELECT "); - queryBuilder.append(selectString); - queryBuilder.append(" FROM \"" + columnFamily + "\""); - queryBuilder.append(whereClause); - if (!order.isEmpty()) { - queryBuilder.append(Util.toString(order, " ORDER BY ", ", ", "")); - } - - int limit = offset; - if (fetch >= 0) { limit += fetch; } - if (limit > 0) { - queryBuilder.append(" LIMIT " + limit); - } - queryBuilder.append(" ALLOW FILTERING"); - final String query = queryBuilder.toString(); - - return new AbstractEnumerable<Object>() { - public Enumerator<Object> enumerator() { - final ResultSet results = session.execute(query); - // Skip results until we get to the right offset - int skip = 0; - Enumerator<Object> enumerator = new CassandraEnumerator(results, resultRowType); - while (skip < offset && enumerator.moveNext()) { skip++; } - - return enumerator; - } - }; - } - - public <T> Queryable<T> asQueryable(QueryProvider queryProvider, - SchemaPlus schema, String tableName) { - return new CassandraQueryable<>(queryProvider, schema, this, tableName); - } - - public RelNode toRel( - RelOptTable.ToRelContext context, - RelOptTable relOptTable) { - final RelOptCluster cluster = context.getCluster(); - return new CassandraTableScan(cluster, cluster.traitSetOf(CassandraRel.CONVENTION), - relOptTable, this, null); - } - - /** Implementation of {@link org.apache.calcite.linq4j.Queryable} based on - * a {@link org.apache.calcite.adapter.cassandra.CassandraTable}. */ - public static class CassandraQueryable<T> extends AbstractTableQueryable<T> { - public CassandraQueryable(QueryProvider queryProvider, SchemaPlus schema, - CassandraTable table, String tableName) { - super(queryProvider, schema, table, tableName); - } - - public Enumerator<T> enumerator() { - //noinspection unchecked - final Enumerable<T> enumerable = - (Enumerable<T>) getTable().query(getSession()); - return enumerable.enumerator(); - } - - private CassandraTable getTable() { - return (CassandraTable) table; - } - - private Session getSession() { - return schema.unwrap(CassandraSchema.class).session; - } - - /** Called via code-generation. - * - * @see org.apache.calcite.adapter.cassandra.CassandraMethod#CASSANDRA_QUERYABLE_QUERY - */ - @SuppressWarnings("UnusedDeclaration") - public Enumerable<Object> query(List<Map.Entry<String, Class>> fields, - List<Map.Entry<String, String>> selectFields, List<String> predicates, - List<String> order, Integer offset, Integer fetch) { - return getTable().query(getSession(), fields, selectFields, predicates, - order, offset, fetch); - } - } -} - -// End CassandraTable.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraTableScan.java ---------------------------------------------------------------------- diff --git a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraTableScan.java b/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraTableScan.java deleted file mode 100644 index 3197d93..0000000 --- a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraTableScan.java +++ /dev/null @@ -1,78 +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.calcite.adapter.cassandra; - -import org.apache.calcite.plan.RelOptCluster; -import org.apache.calcite.plan.RelOptPlanner; -import org.apache.calcite.plan.RelOptRule; -import org.apache.calcite.plan.RelOptTable; -import org.apache.calcite.plan.RelTraitSet; -import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.core.TableScan; -import org.apache.calcite.rel.type.RelDataType; - -import java.util.List; - -/** - * Relational expression representing a scan of a Cassandra collection. - */ -public class CassandraTableScan extends TableScan implements CassandraRel { - final CassandraTable cassandraTable; - final RelDataType projectRowType; - - /** - * Creates a CassandraTableScan. - * - * @param cluster Cluster - * @param traitSet Traits - * @param table Table - * @param cassandraTable Cassandra table - * @param projectRowType Fields and types to project; null to project raw row - */ - protected CassandraTableScan(RelOptCluster cluster, RelTraitSet traitSet, - RelOptTable table, CassandraTable cassandraTable, RelDataType projectRowType) { - super(cluster, traitSet, table); - this.cassandraTable = cassandraTable; - this.projectRowType = projectRowType; - - assert cassandraTable != null; - assert getConvention() == CassandraRel.CONVENTION; - } - - @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) { - assert inputs.isEmpty(); - return this; - } - - @Override public RelDataType deriveRowType() { - return projectRowType != null ? projectRowType : super.deriveRowType(); - } - - @Override public void register(RelOptPlanner planner) { - planner.addRule(CassandraToEnumerableConverterRule.INSTANCE); - for (RelOptRule rule : CassandraRules.RULES) { - planner.addRule(rule); - } - } - - public void implement(Implementor implementor) { - implementor.cassandraTable = cassandraTable; - implementor.table = table; - } -} - -// End CassandraTableScan.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraToEnumerableConverter.java ---------------------------------------------------------------------- diff --git a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraToEnumerableConverter.java b/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraToEnumerableConverter.java deleted file mode 100644 index 66db1ff..0000000 --- a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraToEnumerableConverter.java +++ /dev/null @@ -1,156 +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.calcite.adapter.cassandra; - -import org.apache.calcite.adapter.enumerable.EnumerableRel; -import org.apache.calcite.adapter.enumerable.EnumerableRelImplementor; -import org.apache.calcite.adapter.enumerable.JavaRowFormat; -import org.apache.calcite.adapter.enumerable.PhysType; -import org.apache.calcite.adapter.enumerable.PhysTypeImpl; -import org.apache.calcite.linq4j.tree.BlockBuilder; -import org.apache.calcite.linq4j.tree.Expression; -import org.apache.calcite.linq4j.tree.Expressions; -import org.apache.calcite.linq4j.tree.MethodCallExpression; -import org.apache.calcite.plan.ConventionTraitDef; -import org.apache.calcite.plan.RelOptCluster; -import org.apache.calcite.plan.RelOptCost; -import org.apache.calcite.plan.RelOptPlanner; -import org.apache.calcite.plan.RelTraitSet; -import org.apache.calcite.prepare.CalcitePrepareImpl; -import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.convert.ConverterImpl; -import org.apache.calcite.rel.metadata.RelMetadataQuery; -import org.apache.calcite.rel.type.RelDataType; -import org.apache.calcite.runtime.Hook; -import org.apache.calcite.util.BuiltInMethod; -import org.apache.calcite.util.Pair; - -import com.google.common.base.Function; -import com.google.common.collect.Lists; - -import java.util.AbstractList; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * Relational expression representing a scan of a table in a Cassandra data source. - */ -public class CassandraToEnumerableConverter - extends ConverterImpl - implements EnumerableRel { - protected CassandraToEnumerableConverter( - RelOptCluster cluster, - RelTraitSet traits, - RelNode input) { - super(cluster, ConventionTraitDef.INSTANCE, traits, input); - } - - @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) { - return new CassandraToEnumerableConverter( - getCluster(), traitSet, sole(inputs)); - } - - @Override public RelOptCost computeSelfCost(RelOptPlanner planner, - RelMetadataQuery mq) { - return super.computeSelfCost(planner, mq).multiplyBy(.1); - } - - public Result implement(EnumerableRelImplementor implementor, Prefer pref) { - // Generates a call to "query" with the appropriate fields and predicates - final BlockBuilder list = new BlockBuilder(); - final CassandraRel.Implementor cassandraImplementor = new CassandraRel.Implementor(); - cassandraImplementor.visitChild(0, getInput()); - final RelDataType rowType = getRowType(); - final PhysType physType = - PhysTypeImpl.of( - implementor.getTypeFactory(), rowType, - pref.prefer(JavaRowFormat.ARRAY)); - final Expression fields = - list.append("fields", - constantArrayList( - Pair.zip(CassandraRules.cassandraFieldNames(rowType), - new AbstractList<Class>() { - @Override public Class get(int index) { - return physType.fieldClass(index); - } - - @Override public int size() { - return rowType.getFieldCount(); - } - }), - Pair.class)); - List<Map.Entry<String, String>> selectList = new ArrayList<Map.Entry<String, String>>(); - for (Map.Entry<String, String> entry - : Pair.zip(cassandraImplementor.selectFields.keySet(), - cassandraImplementor.selectFields.values())) { - selectList.add(entry); - } - final Expression selectFields = - list.append("selectFields", constantArrayList(selectList, Pair.class)); - final Expression table = - list.append("table", - cassandraImplementor.table.getExpression( - CassandraTable.CassandraQueryable.class)); - final Expression predicates = - list.append("predicates", - constantArrayList(cassandraImplementor.whereClause, String.class)); - final Expression order = - list.append("order", - constantArrayList(cassandraImplementor.order, String.class)); - final Expression offset = - list.append("offset", - Expressions.constant(cassandraImplementor.offset)); - final Expression fetch = - list.append("fetch", - Expressions.constant(cassandraImplementor.fetch)); - Expression enumerable = - list.append("enumerable", - Expressions.call(table, - CassandraMethod.CASSANDRA_QUERYABLE_QUERY.method, fields, - selectFields, predicates, order, offset, fetch)); - if (CalcitePrepareImpl.DEBUG) { - System.out.println("Cassandra: " + predicates); - } - Hook.QUERY_PLAN.run(predicates); - list.add( - Expressions.return_(null, enumerable)); - return implementor.result(physType, list.toBlock()); - } - - /** E.g. {@code constantArrayList("x", "y")} returns - * "Arrays.asList('x', 'y')". */ - private static <T> MethodCallExpression constantArrayList(List<T> values, - Class clazz) { - return Expressions.call( - BuiltInMethod.ARRAYS_AS_LIST.method, - Expressions.newArrayInit(clazz, constantList(values))); - } - - /** E.g. {@code constantList("x", "y")} returns - * {@code {ConstantExpression("x"), ConstantExpression("y")}}. */ - private static <T> List<Expression> constantList(List<T> values) { - return Lists.transform(values, - new Function<T, Expression>() { - public Expression apply(T a0) { - return Expressions.constant(a0); - } - }); - } -} - -// End CassandraToEnumerableConverter.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraToEnumerableConverterRule.java ---------------------------------------------------------------------- diff --git a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraToEnumerableConverterRule.java b/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraToEnumerableConverterRule.java deleted file mode 100644 index 2ded8c8..0000000 --- a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/CassandraToEnumerableConverterRule.java +++ /dev/null @@ -1,43 +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.calcite.adapter.cassandra; - -import org.apache.calcite.adapter.enumerable.EnumerableConvention; -import org.apache.calcite.plan.RelTraitSet; -import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.convert.ConverterRule; - -/** - * Rule to convert a relational expression from - * {@link CassandraRel#CONVENTION} to {@link EnumerableConvention}. - */ -public class CassandraToEnumerableConverterRule extends ConverterRule { - public static final ConverterRule INSTANCE = - new CassandraToEnumerableConverterRule(); - - private CassandraToEnumerableConverterRule() { - super(RelNode.class, CassandraRel.CONVENTION, EnumerableConvention.INSTANCE, - "CassandraToEnumerableConverterRule"); - } - - @Override public RelNode convert(RelNode rel) { - RelTraitSet newTraitSet = rel.getTraitSet().replace(getOutConvention()); - return new CassandraToEnumerableConverter(rel.getCluster(), newTraitSet, rel); - } -} - -// End CassandraToEnumerableConverterRule.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/package-info.java ---------------------------------------------------------------------- diff --git a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/package-info.java b/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/package-info.java deleted file mode 100644 index c4be45a..0000000 --- a/cassandra/src/main/java/org/apache/calcite/adapter/cassandra/package-info.java +++ /dev/null @@ -1,28 +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. - */ - -/** - * Cassandra query provider. - * - * <p>There is one table for each Cassandra column family.</p> - */ -@PackageMarker -package org.apache.calcite.adapter.cassandra; - -import org.apache.calcite.avatica.util.PackageMarker; - -// End package-info.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/test/java/org/apache/calcite/test/CassandraAdapterIT.java ---------------------------------------------------------------------- diff --git a/cassandra/src/test/java/org/apache/calcite/test/CassandraAdapterIT.java b/cassandra/src/test/java/org/apache/calcite/test/CassandraAdapterIT.java deleted file mode 100644 index bca9233..0000000 --- a/cassandra/src/test/java/org/apache/calcite/test/CassandraAdapterIT.java +++ /dev/null @@ -1,171 +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.calcite.test; - -import org.apache.calcite.util.Util; - -import com.google.common.collect.ImmutableMap; - -import org.junit.Test; - -/** - * Tests for the {@code org.apache.calcite.adapter.cassandra} package. - * - * <p>Before calling this test, you need to populate Cassandra, as follows: - * - * <blockquote><code> - * git clone https://github.com/vlsi/calcite-test-dataset<br> - * cd calcite-test-dataset<br> - * mvn install - * </code></blockquote> - * - * <p>This will create a virtual machine with Cassandra and the "twissandra" - * test data set. - */ -public class CassandraAdapterIT { - /** Connection factory based on the "mongo-zips" model. */ - public static final ImmutableMap<String, String> TWISSANDRA = - ImmutableMap.of("model", - CassandraAdapterIT.class.getResource("/model.json") - .getPath()); - - /** Whether to run Cassandra tests. Enabled by default, however test is only - * included if "it" profile is activated ({@code -Pit}). To disable, - * specify {@code -Dcalcite.test.cassandra=false} on the Java command line. */ - public static final boolean ENABLED = - Util.getBooleanProperty("calcite.test.cassandra", true); - - /** Whether to run this test. */ - protected boolean enabled() { - return ENABLED; - } - - @Test public void testSelect() { - CalciteAssert.that() - .enable(enabled()) - .with(TWISSANDRA) - .query("select * from \"users\"") - .returnsCount(10); - } - - @Test public void testFilter() { - CalciteAssert.that() - .enable(enabled()) - .with(TWISSANDRA) - .query("select * from \"userline\" where \"username\"='!PUBLIC!'") - .limit(1) - .returns("username=!PUBLIC!; time=e8754000-80b8-1fe9-8e73-e3698c967ddd; " - + "tweet_id=f3c329de-d05b-11e5-b58b-90e2ba530b12\n") - .explainContains("PLAN=CassandraToEnumerableConverter\n" - + " CassandraFilter(condition=[=($0, '!PUBLIC!')])\n" - + " CassandraTableScan(table=[[twissandra, userline]]"); - } - - @Test public void testFilterUUID() { - CalciteAssert.that() - .enable(enabled()) - .with(TWISSANDRA) - .query("select * from \"tweets\" where \"tweet_id\"='f3cd759c-d05b-11e5-b58b-90e2ba530b12'") - .limit(1) - .returns("tweet_id=f3cd759c-d05b-11e5-b58b-90e2ba530b12; " - + "body=Lacus augue pede posuere.; username=JmuhsAaMdw\n") - .explainContains("PLAN=CassandraToEnumerableConverter\n" - + " CassandraFilter(condition=[=(CAST($0):CHAR(36) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'f3cd759c-d05b-11e5-b58b-90e2ba530b12')])\n" - + " CassandraTableScan(table=[[twissandra, tweets]]"); - } - - @Test public void testSort() { - CalciteAssert.that() - .enable(enabled()) - .with(TWISSANDRA) - .query("select * from \"userline\" where \"username\" = '!PUBLIC!' order by \"time\" desc") - .returnsCount(146) - .explainContains("PLAN=CassandraToEnumerableConverter\n" - + " CassandraSort(sort0=[$1], dir0=[DESC])\n" - + " CassandraFilter(condition=[=($0, '!PUBLIC!')])\n"); - } - - @Test public void testProject() { - CalciteAssert.that() - .enable(enabled()) - .with(TWISSANDRA) - .query("select \"tweet_id\" from \"userline\" where \"username\" = '!PUBLIC!' limit 2") - .returns("tweet_id=f3c329de-d05b-11e5-b58b-90e2ba530b12\n" - + "tweet_id=f3dbb03a-d05b-11e5-b58b-90e2ba530b12\n") - .explainContains("PLAN=CassandraToEnumerableConverter\n" - + " CassandraLimit(fetch=[2])\n" - + " CassandraProject(tweet_id=[$2])\n" - + " CassandraFilter(condition=[=($0, '!PUBLIC!')])\n"); - } - - @Test public void testProjectAlias() { - CalciteAssert.that() - .enable(enabled()) - .with(TWISSANDRA) - .query("select \"tweet_id\" as \"foo\" from \"userline\" " - + "where \"username\" = '!PUBLIC!' limit 1") - .returns("foo=f3c329de-d05b-11e5-b58b-90e2ba530b12\n"); - } - - @Test public void testProjectConstant() { - CalciteAssert.that() - .enable(enabled()) - .with(TWISSANDRA) - .query("select 'foo' as \"bar\" from \"userline\" limit 1") - .returns("bar=foo\n"); - } - - @Test public void testLimit() { - CalciteAssert.that() - .enable(enabled()) - .with(TWISSANDRA) - .query("select \"tweet_id\" from \"userline\" where \"username\" = '!PUBLIC!' limit 8") - .explainContains("CassandraLimit(fetch=[8])\n"); - } - - @Test public void testSortLimit() { - CalciteAssert.that() - .enable(enabled()) - .with(TWISSANDRA) - .query("select * from \"userline\" where \"username\"='!PUBLIC!' " - + "order by \"time\" desc limit 10") - .explainContains(" CassandraLimit(fetch=[10])\n" - + " CassandraSort(sort0=[$1], dir0=[DESC])"); - } - - @Test public void testSortOffset() { - CalciteAssert.that() - .enable(enabled()) - .with(TWISSANDRA) - .query("select \"tweet_id\" from \"userline\" where " - + "\"username\"='!PUBLIC!' limit 2 offset 1") - .explainContains("CassandraLimit(offset=[1], fetch=[2])") - .returns("tweet_id=f3dbb03a-d05b-11e5-b58b-90e2ba530b12\n" - + "tweet_id=f3e4182e-d05b-11e5-b58b-90e2ba530b12\n"); - } - - @Test public void testMaterializedView() { - CalciteAssert.that() - .enable(enabled()) - .with(TWISSANDRA) - .query("select \"tweet_id\" from \"tweets\" where \"username\"='JmuhsAaMdw'") - .enableMaterializations(true) - .explainContains("CassandraTableScan(table=[[twissandra, tweets_by_user]])"); - } -} - -// End CassandraAdapterIT.java http://git-wip-us.apache.org/repos/asf/calcite-avatica/blob/fc7b26c8/cassandra/src/test/resources/model.json ---------------------------------------------------------------------- diff --git a/cassandra/src/test/resources/model.json b/cassandra/src/test/resources/model.json deleted file mode 100644 index 5713d11..0000000 --- a/cassandra/src/test/resources/model.json +++ /dev/null @@ -1,31 +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. - */ -{ - "version": "1.0", - "defaultSchema": "twissandra", - "schemas": [ - { - "name": "twissandra", - "type": "custom", - "factory": "org.apache.calcite.adapter.cassandra.CassandraSchemaFactory", - "operand": { - "host": "localhost", - "keyspace": "twissandra" - } - } - ] -}
