Skip to content

Instantly share code, notes, and snippets.

@junwen12221
Created March 18, 2021 13:21
Show Gist options
  • Save junwen12221/c6526756715735861a51a8890eb637ff to your computer and use it in GitHub Desktop.
Save junwen12221/c6526756715735861a51a8890eb637ff to your computer and use it in GitHub Desktop.
package io.mycat.calcite.rewriter;
import io.mycat.calcite.logical.MycatView;
import org.apache.calcite.plan.Contexts;
import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.plan.RelRule;
import org.apache.calcite.rel.core.Join;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.logical.LogicalJoin;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rex.RexBuilder;
import org.apache.calcite.rex.RexInputRef;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexShuttle;
import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.tools.RelBuilderFactory;
import org.apache.calcite.util.ImmutableBeans;
import java.util.List;
public class JoinTernaryCommuteRule extends RelRule<JoinTernaryCommuteRule.Config> {
/**
* Creates a JoinCommuteRule.
*/
protected JoinTernaryCommuteRule(JoinTernaryCommuteRule.Config config) {
super(config);
}
@Deprecated // to be removed before 2.0
public JoinTernaryCommuteRule(Class<? extends Join> clazz,
RelBuilderFactory relBuilderFactory, boolean swapOuter) {
this(JoinTernaryCommuteRule.Config.DEFAULT.withRelBuilderFactory(relBuilderFactory)
.as(JoinTernaryCommuteRule.Config.class)
.withOperandFor(clazz)
.withSwapOuter(swapOuter));
}
@Deprecated // to be removed before 2.0
public JoinTernaryCommuteRule(Class<? extends Join> clazz,
RelFactories.ProjectFactory projectFactory) {
this(clazz, RelBuilder.proto(Contexts.of(projectFactory)), false);
}
@Deprecated // to be removed before 2.0
public JoinTernaryCommuteRule(Class<? extends Join> clazz,
RelFactories.ProjectFactory projectFactory, boolean swapOuter) {
this(clazz, RelBuilder.proto(Contexts.of(projectFactory)), swapOuter);
}
@Override
public boolean matches(RelOptRuleCall call) {
Join join = call.rel(0);
// SEMI and ANTI join cannot be swapped.
return join.getJoinType().projectsRight();
}
@Override
public void onMatch(final RelOptRuleCall call) {
LogicalJoin rootJoin = call.rel(0);
LogicalJoin leftjoin = call.rel(0);
System.out.println();
// final RelNode swapped = swap(join, config.isSwapOuter(), call.builder());
// if (swapped == null) {
// return;
// }
//
// // The result is either a Project or, if the project is trivial, a
// // raw Join.
// final Join newJoin =
// swapped instanceof Join
// ? (Join) swapped
// : (Join) swapped.getInput(0);
//
// call.transformTo(swapped);
//
// // We have converted join='a join b' into swapped='select
// // a0,a1,a2,b0,b1 from b join a'. Now register that project='select
// // b0,b1,a0,a1,a2 from (select a0,a1,a2,b0,b1 from b join a)' is the
// // same as 'b join a'. If we didn't do this, the swap join rule
// // would fire on the new join, ad infinitum.
// final RelBuilder relBuilder = call.builder();
// final List<RexNode> exps =
// RelOptUtil.createSwappedJoinExprs(newJoin, join, false);
// relBuilder.push(swapped)
// .project(exps, newJoin.getRowType().getFieldNames());
//
// call.getPlanner().ensureRegistered(relBuilder.build(), newJoin);
}
//~ Inner Classes ----------------------------------------------------------
/**
* Walks over an expression, replacing references to fields of the left and
* right inputs.
*
* <p>If the field index is less than leftFieldCount, it must be from the
* left, and so has rightFieldCount added to it; if the field index is
* greater than leftFieldCount, it must be from the right, so we subtract
* leftFieldCount from it.</p>
*/
private static class VariableReplacer extends RexShuttle {
private final RexBuilder rexBuilder;
private final List<RelDataTypeField> leftFields;
private final List<RelDataTypeField> rightFields;
VariableReplacer(
RexBuilder rexBuilder,
RelDataType leftType,
RelDataType rightType) {
this.rexBuilder = rexBuilder;
this.leftFields = leftType.getFieldList();
this.rightFields = rightType.getFieldList();
}
@Override
public RexNode visitInputRef(RexInputRef inputRef) {
int index = inputRef.getIndex();
if (index < leftFields.size()) {
// Field came from left side of join. Move it to the right.
return rexBuilder.makeInputRef(
leftFields.get(index).getType(),
rightFields.size() + index);
}
index -= leftFields.size();
if (index < rightFields.size()) {
// Field came from right side of join. Move it to the left.
return rexBuilder.makeInputRef(
rightFields.get(index).getType(),
index);
}
throw new AssertionError("Bad field offset: index=" + inputRef.getIndex()
+ ", leftFieldCount=" + leftFields.size()
+ ", rightFieldCount=" + rightFields.size());
}
}
/**
* Rule configuration.
*/
public interface Config extends RelRule.Config {
JoinTernaryCommuteRule.Config DEFAULT = EMPTY.as(JoinTernaryCommuteRule.Config.class)
.withOperandFor(Join.class)
.withSwapOuter(false);
@Override
default JoinTernaryCommuteRule toRule() {
return new JoinTernaryCommuteRule(this);
}
/**
* Defines an operand tree for the given classes.
*/
default JoinTernaryCommuteRule.Config withOperandFor(Class<? extends Join> joinClass) {
return withOperandSupplier(b ->
b.operand(joinClass).inputs(b1 -> b1.operand(joinClass)
.inputs(d -> d.operand(MycatView.class).noInputs(), d -> d.operand(MycatView.class).noInputs()),
d -> d.operand(MycatView.class).noInputs()))
.as(JoinTernaryCommuteRule.Config.class);
}
/**
* Whether to swap outer joins.
*/
@ImmutableBeans.Property
@ImmutableBeans.BooleanDefault(false)
boolean isSwapOuter();
/**
* Sets {@link #isSwapOuter()}.
*/
JoinTernaryCommuteRule.Config withSwapOuter(boolean swapOuter);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment