All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.org.apache.calcite.prepare.LixToRelTranslator Maven / Gradle / Ivy

There is a newer version: 5.4.0
Show newest version
/*
 * 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 com.hazelcast.org.apache.calcite.prepare;

import com.hazelcast.org.apache.calcite.adapter.java.JavaTypeFactory;
import com.hazelcast.org.apache.calcite.linq4j.Queryable;
import com.hazelcast.org.apache.calcite.linq4j.tree.BlockStatement;
import com.hazelcast.org.apache.calcite.linq4j.tree.Blocks;
import com.hazelcast.org.apache.calcite.linq4j.tree.ConstantExpression;
import com.hazelcast.org.apache.calcite.linq4j.tree.Expression;
import com.hazelcast.org.apache.calcite.linq4j.tree.FunctionExpression;
import com.hazelcast.org.apache.calcite.linq4j.tree.MethodCallExpression;
import com.hazelcast.org.apache.calcite.linq4j.tree.NewExpression;
import com.hazelcast.org.apache.calcite.linq4j.tree.ParameterExpression;
import com.hazelcast.org.apache.calcite.linq4j.tree.Types;
import com.hazelcast.org.apache.calcite.plan.RelOptCluster;
import com.hazelcast.org.apache.calcite.plan.RelOptTable;
import com.hazelcast.org.apache.calcite.plan.ViewExpanders;
import com.hazelcast.org.apache.calcite.rel.RelNode;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalFilter;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalProject;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalTableScan;
import com.hazelcast.org.apache.calcite.rex.RexBuilder;
import com.hazelcast.org.apache.calcite.rex.RexNode;
import com.hazelcast.org.apache.calcite.util.BuiltInMethod;

import com.hazelcast.com.google.common.collect.ImmutableList;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static java.util.Objects.requireNonNull;

/**
 * Translates a tree of linq4j {@link Queryable} nodes to a tree of
 * {@link RelNode} planner nodes.
 *
 * @see QueryableRelBuilder
 */
class LixToRelTranslator {
  final RelOptCluster cluster;
  private final Prepare preparingStmt;
  final JavaTypeFactory typeFactory;

  LixToRelTranslator(RelOptCluster cluster, Prepare preparingStmt) {
    this.cluster = cluster;
    this.preparingStmt = preparingStmt;
    this.typeFactory = (JavaTypeFactory) cluster.getTypeFactory();
  }

  private static BlockStatement getBody(FunctionExpression expression) {
    return requireNonNull(expression.body, () -> "body in " + expression);
  }

  private static List getParameterList(FunctionExpression expression) {
    return requireNonNull(expression.parameterList, () -> "parameterList in " + expression);
  }

  private static Expression getTargetExpression(MethodCallExpression call) {
    return requireNonNull(call.targetExpression,
        "translation of static calls is not supported yet");
  }

  RelOptTable.ToRelContext toRelContext() {
    if (preparingStmt instanceof RelOptTable.ViewExpander) {
      final RelOptTable.ViewExpander viewExpander =
          (RelOptTable.ViewExpander) this.preparingStmt;
      return ViewExpanders.toRelContext(viewExpander, cluster);
    } else {
      return ViewExpanders.simpleContext(cluster);
    }
  }

  public  RelNode translate(Queryable queryable) {
    QueryableRelBuilder translatorQueryable =
        new QueryableRelBuilder<>(this);
    return translatorQueryable.toRel(queryable);
  }

  public RelNode translate(Expression expression) {
    if (expression instanceof MethodCallExpression) {
      final MethodCallExpression call = (MethodCallExpression) expression;
      BuiltInMethod method = BuiltInMethod.MAP.get(call.method);
      if (method == null) {
        throw new UnsupportedOperationException(
            "unknown method " + call.method);
      }
      RelNode input;
      switch (method) {
      case SELECT:
        input = translate(getTargetExpression(call));
        return LogicalProject.create(input,
            ImmutableList.of(),
            toRex(input, (FunctionExpression) call.expressions.get(0)),
            (List) null);

      case WHERE:
        input = translate(getTargetExpression(call));
        return LogicalFilter.create(input,
            toRex((FunctionExpression) call.expressions.get(0), input));

      case AS_QUERYABLE:
        return LogicalTableScan.create(cluster,
            RelOptTableImpl.create(null,
                typeFactory.createJavaType(
                    Types.toClass(
                        getElementType(call))),
                ImmutableList.of(),
                getTargetExpression(call)),
            ImmutableList.of());

      case SCHEMA_GET_TABLE:
        return LogicalTableScan.create(cluster,
            RelOptTableImpl.create(null,
                typeFactory.createJavaType((Class)
                    requireNonNull(
                        ((ConstantExpression) call.expressions.get(1)).value,
                        "argument 1 (0-based) is null Class")),
                ImmutableList.of(),
                getTargetExpression(call)),
            ImmutableList.of());

      default:
        throw new UnsupportedOperationException(
            "unknown method " + call.method);
      }
    }
    throw new UnsupportedOperationException(
        "unknown expression type " + expression.getNodeType());
  }

  private static Type getElementType(MethodCallExpression call) {
    Type type = getTargetExpression(call).getType();
    return requireNonNull(
        Types.getElementType(type),
        () -> "unable to figure out element type from " + type);
  }

  private List toRex(
      RelNode child, FunctionExpression expression) {
    RexBuilder rexBuilder = cluster.getRexBuilder();
    List list =
        Collections.singletonList(
            rexBuilder.makeRangeReference(child));
    CalcitePrepareImpl.ScalarTranslator translator =
        CalcitePrepareImpl.EmptyScalarTranslator
            .empty(rexBuilder)
            .bind(getParameterList(expression), list);
    final List rexList = new ArrayList<>();
    final Expression simple = Blocks.simple(getBody(expression));
    for (Expression expression1 : fieldExpressions(simple)) {
      rexList.add(translator.toRex(expression1));
    }
    return rexList;
  }

  List fieldExpressions(Expression expression) {
    if (expression instanceof NewExpression) {
      // Note: We are assuming that the arguments to the constructor
      // are the same order as the fields of the class.
      return ((NewExpression) expression).arguments;
    }
    throw new RuntimeException(
        "unsupported expression type " + expression);
  }

  List toRexList(
      FunctionExpression expression,
      RelNode... inputs) {
    List list = new ArrayList<>();
    RexBuilder rexBuilder = cluster.getRexBuilder();
    for (RelNode input : inputs) {
      list.add(rexBuilder.makeRangeReference(input));
    }
    return CalcitePrepareImpl.EmptyScalarTranslator.empty(rexBuilder)
        .bind(getParameterList(expression), list)
        .toRexList(getBody(expression));
  }

  RexNode toRex(
      FunctionExpression expression,
      RelNode... inputs) {
    List list = new ArrayList<>();
    RexBuilder rexBuilder = cluster.getRexBuilder();
    for (RelNode input : inputs) {
      list.add(rexBuilder.makeRangeReference(input));
    }
    return CalcitePrepareImpl.EmptyScalarTranslator.empty(rexBuilder)
        .bind(getParameterList(expression), list)
        .toRex(getBody(expression));
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy