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

com.hazelcast.org.apache.calcite.rel.rules.UnionMergeRule 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 com.hazelcast.com.liance with
 * the License.  You may obtain a copy of the License at
 *
 * http://www.apache.com.hazelcast.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.rel.rules;

import com.hazelcast.org.apache.calcite.plan.RelOptRule;
import com.hazelcast.org.apache.calcite.plan.RelOptRuleCall;
import com.hazelcast.org.apache.calcite.rel.RelNode;
import com.hazelcast.org.apache.calcite.rel.core.Intersect;
import com.hazelcast.org.apache.calcite.rel.core.Minus;
import com.hazelcast.org.apache.calcite.rel.core.RelFactories;
import com.hazelcast.org.apache.calcite.rel.core.SetOp;
import com.hazelcast.org.apache.calcite.rel.core.Union;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalIntersect;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalMinus;
import com.hazelcast.org.apache.calcite.rel.logical.LogicalUnion;
import com.hazelcast.org.apache.calcite.tools.RelBuilder;
import com.hazelcast.org.apache.calcite.tools.RelBuilderFactory;
import com.hazelcast.org.apache.calcite.util.Util;

/**
 * UnionMergeRule implements the rule for com.hazelcast.com.ining two
 * non-distinct {@link com.hazelcast.org.apache.calcite.rel.core.SetOp}s
 * into a single {@link com.hazelcast.org.apache.calcite.rel.core.SetOp}.
 *
 * 

Originally written for {@link Union} (hence the name), * but now also applies to {@link Intersect}. */ public class UnionMergeRule extends RelOptRule implements TransformationRule { public static final UnionMergeRule INSTANCE = new UnionMergeRule(LogicalUnion.class, "UnionMergeRule", RelFactories.LOGICAL_BUILDER); public static final UnionMergeRule INTERSECT_INSTANCE = new UnionMergeRule(LogicalIntersect.class, "IntersectMergeRule", RelFactories.LOGICAL_BUILDER); public static final UnionMergeRule MINUS_INSTANCE = new UnionMergeRule(LogicalMinus.class, "MinusMergeRule", RelFactories.LOGICAL_BUILDER); //~ Constructors ----------------------------------------------------------- /** Creates a UnionMergeRule. */ public UnionMergeRule(Class unionClazz, String description, RelBuilderFactory relBuilderFactory) { super( operand(unionClazz, operand(RelNode.class, any()), operand(RelNode.class, any())), relBuilderFactory, description); } @Deprecated // to be removed before 2.0 public UnionMergeRule(Class unionClazz, RelFactories.SetOpFactory setOpFactory) { this(unionClazz, null, RelBuilder.proto(setOpFactory)); } //~ Methods ---------------------------------------------------------------- @Override public boolean matches(RelOptRuleCall call) { // It avoids adding the rule match to the match queue in case the rule is known to be a no-op final SetOp topOp = call.rel(0); @SuppressWarnings("unchecked") final Class setOpClass = (Class) operands.get(0).getMatchedClass(); final SetOp bottomOp; if (setOpClass.isInstance(call.rel(2)) && !Minus.class.isAssignableFrom(setOpClass)) { bottomOp = call.rel(2); } else if (setOpClass.isInstance(call.rel(1))) { bottomOp = call.rel(1); } else { return false; } if (topOp.all && !bottomOp.all) { return false; } return true; } public void onMatch(RelOptRuleCall call) { final SetOp topOp = call.rel(0); @SuppressWarnings("unchecked") final Class setOpClass = (Class) operands.get(0).getMatchedClass(); // For Union and Intersect, we want to com.hazelcast.com.ine the set-op that's in the // second input first. // // For example, we reduce // Union(Union(a, b), Union(c, d)) // to // Union(Union(a, b), c, d) // in preference to // Union(a, b, Union(c, d)) // // But for Minus, we can only reduce the left input. It is not valid to // reduce // Minus(a, Minus(b, c)) // to // Minus(a, b, c) // // Hence, that's why the rule pattern matches on generic RelNodes rather // than explicit sub-classes of SetOp. By doing so, and firing this rule // in a bottom-up order, it allows us to only specify a single // pattern for this rule. final SetOp bottomOp; if (setOpClass.isInstance(call.rel(2)) && !Minus.class.isAssignableFrom(setOpClass)) { bottomOp = call.rel(2); } else if (setOpClass.isInstance(call.rel(1))) { bottomOp = call.rel(1); } else { return; } // Can only com.hazelcast.com.ine (1) if all operators are ALL, // or (2) top operator is DISTINCT (i.e. not ALL). // In case (2), all operators become DISTINCT. if (topOp.all && !bottomOp.all) { return; } // Combine the inputs from the bottom set-op with the other inputs from // the top set-op. final RelBuilder relBuilder = call.builder(); if (setOpClass.isInstance(call.rel(2)) && !Minus.class.isAssignableFrom(setOpClass)) { relBuilder.push(topOp.getInput(0)); relBuilder.pushAll(bottomOp.getInputs()); // topOp.getInputs().size() may be more than 2 for (int index = 2; index < topOp.getInputs().size(); index++) { relBuilder.push(topOp.getInput(index)); } } else { relBuilder.pushAll(bottomOp.getInputs()); relBuilder.pushAll(Util.skip(topOp.getInputs())); } int n = bottomOp.getInputs().size() + topOp.getInputs().size() - 1; if (topOp instanceof Union) { relBuilder.union(topOp.all, n); } else if (topOp instanceof Intersect) { relBuilder.intersect(topOp.all, n); } else if (topOp instanceof Minus) { relBuilder.minus(topOp.all, n); } call.transformTo(relBuilder.build()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy