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

com.hazelcast.org.apache.calcite.rex.RexTransformer 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.rex;

import com.hazelcast.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.org.apache.calcite.sql.SqlKind;
import com.hazelcast.org.apache.calcite.sql.SqlOperator;
import com.hazelcast.org.apache.calcite.sql.fun.SqlStdOperatorTable;
import com.hazelcast.org.apache.calcite.sql.type.SqlTypeUtil;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

/**
 * Takes a tree of {@link RexNode} objects and transforms it into another in one
 * sense equivalent tree. Nodes in tree will be modified and hence tree will not
 * remain unchanged.
 *
 * 

NOTE: You must validate the tree of RexNodes before using this class. */ public class RexTransformer { //~ Instance fields -------------------------------------------------------- private RexNode root; private final RexBuilder rexBuilder; private int isParentsCount; private final Set transformableOperators = new HashSet<>(); //~ Constructors ----------------------------------------------------------- public RexTransformer( RexNode root, RexBuilder rexBuilder) { this.root = root; this.rexBuilder = rexBuilder; isParentsCount = 0; transformableOperators.add(SqlStdOperatorTable.AND); /** NOTE the OR operator is NOT missing. * see {@link com.hazelcast.org.apache.calcite.test.RexTransformerTest} */ transformableOperators.add(SqlStdOperatorTable.EQUALS); transformableOperators.add(SqlStdOperatorTable.NOT_EQUALS); transformableOperators.add(SqlStdOperatorTable.GREATER_THAN); transformableOperators.add( SqlStdOperatorTable.GREATER_THAN_OR_EQUAL); transformableOperators.add(SqlStdOperatorTable.LESS_THAN); transformableOperators.add(SqlStdOperatorTable.LESS_THAN_OR_EQUAL); } //~ Methods ---------------------------------------------------------------- private static boolean isBoolean(RexNode node) { RelDataType type = node.getType(); return SqlTypeUtil.inBooleanFamily(type); } private static boolean isNullable(RexNode node) { return node.getType().isNullable(); } private boolean isTransformable(RexNode node) { if (0 == isParentsCount) { return false; } if (node instanceof RexCall) { RexCall call = (RexCall) node; return !transformableOperators.contains( call.getOperator()) && isNullable(node); } return isNullable(node); } public RexNode transformNullSemantics() { root = transformNullSemantics(root); return root; } private RexNode transformNullSemantics(RexNode node) { assert isParentsCount >= 0 : "Cannot be negative"; if (!isBoolean(node)) { return node; } Boolean directlyUnderIs = null; if (node.isA(SqlKind.IS_TRUE)) { directlyUnderIs = Boolean.TRUE; isParentsCount++; } else if (node.isA(SqlKind.IS_FALSE)) { directlyUnderIs = Boolean.FALSE; isParentsCount++; } // Special case when we have a Literal, Parameter or Identifier directly // as an operand to IS TRUE or IS FALSE. if (null != directlyUnderIs) { RexCall call = (RexCall) node; assert isParentsCount > 0 : "Stack should not be empty"; assert 1 == call.operands.size(); RexNode operand = call.operands.get(0); if (operand instanceof RexLiteral || operand instanceof RexInputRef || operand instanceof RexDynamicParam) { if (isNullable(node)) { RexNode notNullNode = rexBuilder.makeCall( SqlStdOperatorTable.IS_NOT_NULL, operand); RexNode boolNode = rexBuilder.makeLiteral( directlyUnderIs.booleanValue()); RexNode eqNode = rexBuilder.makeCall( SqlStdOperatorTable.EQUALS, operand, boolNode); RexNode andBoolNode = rexBuilder.makeCall( SqlStdOperatorTable.AND, notNullNode, eqNode); return andBoolNode; } else { RexNode boolNode = rexBuilder.makeLiteral( directlyUnderIs.booleanValue()); RexNode andBoolNode = rexBuilder.makeCall( SqlStdOperatorTable.EQUALS, node, boolNode); return andBoolNode; } } // else continue as normal } if (node instanceof RexCall) { RexCall call = (RexCall) node; // Transform children (if any) before transforming node itself. final ArrayList operands = new ArrayList<>(); for (RexNode operand : call.operands) { operands.add(transformNullSemantics(operand)); } if (null != directlyUnderIs) { isParentsCount--; directlyUnderIs = null; return operands.get(0); } if (transformableOperators.contains(call.getOperator())) { assert 2 == operands.size(); final RexNode isNotNullOne; if (isTransformable(operands.get(0))) { isNotNullOne = rexBuilder.makeCall( SqlStdOperatorTable.IS_NOT_NULL, operands.get(0)); } else { isNotNullOne = null; } final RexNode isNotNullTwo; if (isTransformable(operands.get(1))) { isNotNullTwo = rexBuilder.makeCall( SqlStdOperatorTable.IS_NOT_NULL, operands.get(1)); } else { isNotNullTwo = null; } RexNode intoFinalAnd = null; if ((null != isNotNullOne) && (null != isNotNullTwo)) { intoFinalAnd = rexBuilder.makeCall( SqlStdOperatorTable.AND, isNotNullOne, isNotNullTwo); } else if (null != isNotNullOne) { intoFinalAnd = isNotNullOne; } else if (null != isNotNullTwo) { intoFinalAnd = isNotNullTwo; } if (null != intoFinalAnd) { RexNode andNullAndCheckNode = rexBuilder.makeCall( SqlStdOperatorTable.AND, intoFinalAnd, call.clone(call.getType(), operands)); return andNullAndCheckNode; } // if come here no need to do anything } if (!operands.equals(call.operands)) { return call.clone(call.getType(), operands); } } return node; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy