| /* |
| * 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.flink.table.plan.nodes |
| |
| import org.apache.flink.table.plan.nodes.ExpressionFormat.ExpressionFormat |
| |
| import org.apache.calcite.rel.RelNode |
| import org.apache.calcite.rex._ |
| import org.apache.calcite.sql.SqlAsOperator |
| import org.apache.calcite.sql.SqlKind._ |
| |
| import scala.collection.JavaConversions._ |
| |
| trait FlinkRelNode extends RelNode { |
| |
| /** |
| * Return true if this rel is a deterministic RelNode which is guaranteed to |
| * always output the same result given the same input. |
| * |
| * <p>NOTES: A deterministic rel should not contain non-deterministic `SqlOperator` |
| * and dynamic function `SqlOperator`. |
| * e.g. |
| * `Filter` is non-deterministic if its condition contains non-deterministic udf, |
| * `Aggregate` is non-deterministic if its aggCalls contain non-deterministic `SqlAggFunction`. |
| */ |
| def isDeterministic: Boolean |
| |
| private[flink] def getExpressionString( |
| expr: RexNode, |
| inFields: List[String], |
| localExprsTable: Option[List[RexNode]]): String = { |
| getExpressionString(expr, inFields, localExprsTable, ExpressionFormat.Prefix) |
| } |
| |
| private[flink] def getExpressionString( |
| expr: RexNode, |
| inFields: List[String], |
| localExprsTable: Option[List[RexNode]], |
| expressionFormat: ExpressionFormat): String = { |
| |
| expr match { |
| case pr: RexPatternFieldRef => |
| val alpha = pr.getAlpha |
| val field = inFields.get(pr.getIndex) |
| s"$alpha.$field" |
| |
| case i: RexInputRef => |
| inFields.get(i.getIndex) |
| |
| case l: RexLiteral => |
| l.toString |
| |
| case l: RexLocalRef if localExprsTable.isEmpty => |
| throw new IllegalArgumentException("Encountered RexLocalRef without " + |
| "local expression table") |
| |
| case l: RexLocalRef => |
| val lExpr = localExprsTable.get(l.getIndex) |
| getExpressionString(lExpr, inFields, localExprsTable, expressionFormat) |
| |
| case c: RexCall => |
| val op = c.getOperator.toString |
| val ops = c.getOperands.map( |
| getExpressionString(_, inFields, localExprsTable, expressionFormat)) |
| c.getOperator match { |
| case _ : SqlAsOperator => ops.head |
| case _ => |
| expressionFormat match { |
| case ExpressionFormat.Infix if ops.size() == 1 => |
| val operand = ops.head |
| c.getKind match { |
| case IS_FALSE | IS_NOT_FALSE | IS_TRUE | IS_NOT_TRUE | IS_UNKNOWN | IS_NULL | |
| IS_NOT_NULL => s"$operand $op" |
| case _ => s"$op($operand)" |
| } |
| case ExpressionFormat.Infix => s"(${ops.mkString(s" $op ")})" |
| case ExpressionFormat.PostFix => s"(${ops.mkString(", ")})$op" |
| case ExpressionFormat.Prefix => s"$op(${ops.mkString(", ")})" |
| } |
| } |
| |
| case fa: RexFieldAccess => |
| val referenceExpr = getExpressionString( |
| fa.getReferenceExpr, |
| inFields, |
| localExprsTable, |
| expressionFormat) |
| val field = fa.getField.getName |
| s"$referenceExpr.$field" |
| case cv: RexCorrelVariable => |
| cv.toString |
| case _ => |
| throw new IllegalArgumentException(s"Unknown expression type '${expr.getClass}': $expr") |
| } |
| } |
| |
| } |
| |
| /** |
| * Infix, Postfix and Prefix notations are three different but equivalent ways of writing |
| * expressions. It is easiest to demonstrate the differences by looking at examples of operators |
| * that take two operands. |
| * Infix notation: (X + Y) |
| * Postfix notation: (X Y) + |
| * Prefix notation: + (X Y) |
| */ |
| object ExpressionFormat extends Enumeration { |
| type ExpressionFormat = Value |
| val Infix, PostFix, Prefix = Value |
| } |