diff --git a/dlink-client/dlink-client-1.11/src/main/java/com/dlink/utils/LineageContext.java b/dlink-client/dlink-client-1.11/src/main/java/com/dlink/utils/LineageContext.java index 87a07eb694..40e4afcc53 100644 --- a/dlink-client/dlink-client-1.11/src/main/java/com/dlink/utils/LineageContext.java +++ b/dlink-client/dlink-client-1.11/src/main/java/com/dlink/utils/LineageContext.java @@ -25,7 +25,6 @@ import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.core.Snapshot; import org.apache.calcite.rel.metadata.RelColumnOrigin; import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.rel.type.RelDataType; @@ -56,11 +55,6 @@ import java.util.Set; import java.util.stream.Collectors; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.Modifier; - /** * LineageContext * @@ -77,33 +71,6 @@ public LineageContext(FlinkChainedProgram flinkChainedProgram, TableEnvironmentI this.tableEnv = tableEnv; } - /** - * Dynamic add getColumnOrigins method to class RelMdColumnOrigins by javassist: - * - * public Set getColumnOrigins(Snapshot rel,RelMetadataQuery mq, int iOutputColumn) { - * return mq.getColumnOrigins(rel.getInput(), iOutputColumn); - * } - */ - static { - try { - ClassPool classPool = ClassPool.getDefault(); - CtClass ctClass = classPool.getCtClass("org.apache.calcite.rel.metadata.RelMdColumnOrigins"); - - CtClass[] parameters = new CtClass[]{classPool.get(Snapshot.class.getName()), - classPool.get(RelMetadataQuery.class.getName()), CtClass.intType - }; - // add method - CtMethod ctMethod = new CtMethod(classPool.get("java.util.Set"), "getColumnOrigins", parameters, ctClass); - ctMethod.setModifiers(Modifier.PUBLIC); - ctMethod.setBody("{return $2.getColumnOrigins($1.getInput(), $3);}"); - ctClass.addMethod(ctMethod); - // load the class - ctClass.toClass(); - } catch (Exception e) { - throw new TableException("Dynamic add getColumnOrigins() method exception.", e); - } - } - public List getLineage(String statement) { // 1. Generate original relNode tree Tuple2 parsed = parseStatement(statement); @@ -178,9 +145,9 @@ public SqlExprToRexConverter create(RelDataType relDataType) { @Override public C unwrap(Class clazz) { - if(clazz.isInterface()){ + if (clazz.isInterface()) { return clazz.cast(this); - }else{ + } else { return null; } } diff --git a/dlink-client/dlink-client-1.12/src/main/java/com/dlink/utils/LineageContext.java b/dlink-client/dlink-client-1.12/src/main/java/com/dlink/utils/LineageContext.java index 838dddd749..40e4afcc53 100644 --- a/dlink-client/dlink-client-1.12/src/main/java/com/dlink/utils/LineageContext.java +++ b/dlink-client/dlink-client-1.12/src/main/java/com/dlink/utils/LineageContext.java @@ -25,7 +25,6 @@ import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.core.Snapshot; import org.apache.calcite.rel.metadata.RelColumnOrigin; import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.rel.type.RelDataType; @@ -56,11 +55,6 @@ import java.util.Set; import java.util.stream.Collectors; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.Modifier; - /** * LineageContext * @@ -77,33 +71,6 @@ public LineageContext(FlinkChainedProgram flinkChainedProgram, TableEnvironmentI this.tableEnv = tableEnv; } - /** - * Dynamic add getColumnOrigins method to class RelMdColumnOrigins by javassist: - * - * public Set getColumnOrigins(Snapshot rel,RelMetadataQuery mq, int iOutputColumn) { - * return mq.getColumnOrigins(rel.getInput(), iOutputColumn); - * } - */ - static { - try { - ClassPool classPool = ClassPool.getDefault(); - CtClass ctClass = classPool.getCtClass("org.apache.calcite.rel.metadata.RelMdColumnOrigins"); - - CtClass[] parameters = new CtClass[]{classPool.get(Snapshot.class.getName()), - classPool.get(RelMetadataQuery.class.getName()), CtClass.intType - }; - // add method - CtMethod ctMethod = new CtMethod(classPool.get("java.util.Set"), "getColumnOrigins", parameters, ctClass); - ctMethod.setModifiers(Modifier.PUBLIC); - ctMethod.setBody("{return $2.getColumnOrigins($1.getInput(), $3);}"); - ctClass.addMethod(ctMethod); - // load the class - ctClass.toClass(); - } catch (Exception e) { - throw new TableException("Dynamic add getColumnOrigins() method exception.", e); - } - } - public List getLineage(String statement) { // 1. Generate original relNode tree Tuple2 parsed = parseStatement(statement); diff --git a/dlink-client/dlink-client-1.13/src/main/java/com/dlink/utils/LineageContext.java b/dlink-client/dlink-client-1.13/src/main/java/com/dlink/utils/LineageContext.java index 8f8b1bdfe9..d67b08305c 100644 --- a/dlink-client/dlink-client-1.13/src/main/java/com/dlink/utils/LineageContext.java +++ b/dlink-client/dlink-client-1.13/src/main/java/com/dlink/utils/LineageContext.java @@ -23,7 +23,6 @@ import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.core.Snapshot; import org.apache.calcite.rel.metadata.RelColumnOrigin; import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.rex.RexBuilder; @@ -48,11 +47,6 @@ import java.util.List; import java.util.Set; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.Modifier; - /** * LineageContext * @@ -69,33 +63,6 @@ public LineageContext(FlinkChainedProgram flinkChainedProgram, TableEnvironmentI this.tableEnv = tableEnv; } - /** - * Dynamic add getColumnOrigins method to class RelMdColumnOrigins by javassist: - * - * public Set getColumnOrigins(Snapshot rel,RelMetadataQuery mq, int iOutputColumn) { - * return mq.getColumnOrigins(rel.getInput(), iOutputColumn); - * } - */ - static { - try { - ClassPool classPool = ClassPool.getDefault(); - CtClass ctClass = classPool.getCtClass("org.apache.calcite.rel.metadata.RelMdColumnOrigins"); - - CtClass[] parameters = new CtClass[]{classPool.get(Snapshot.class.getName()), - classPool.get(RelMetadataQuery.class.getName()), CtClass.intType - }; - // add method - CtMethod ctMethod = new CtMethod(classPool.get("java.util.Set"), "getColumnOrigins", parameters, ctClass); - ctMethod.setModifiers(Modifier.PUBLIC); - ctMethod.setBody("{return $2.getColumnOrigins($1.getInput(), $3);}"); - ctClass.addMethod(ctMethod); - // load the class - ctClass.toClass(); - } catch (Exception e) { - throw new TableException("Dynamic add getColumnOrigins() method exception.", e); - } - } - public List getLineage(String statement) { // 1. Generate original relNode tree Tuple2 parsed = parseStatement(statement); diff --git a/dlink-client/dlink-client-1.14/src/main/java/com/dlink/utils/LineageContext.java b/dlink-client/dlink-client-1.14/src/main/java/com/dlink/utils/LineageContext.java index ab527e5ebd..a9a9259961 100644 --- a/dlink-client/dlink-client-1.14/src/main/java/com/dlink/utils/LineageContext.java +++ b/dlink-client/dlink-client-1.14/src/main/java/com/dlink/utils/LineageContext.java @@ -23,7 +23,6 @@ import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.core.Snapshot; import org.apache.calcite.rel.metadata.RelColumnOrigin; import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.commons.collections.CollectionUtils; @@ -48,11 +47,6 @@ import java.util.List; import java.util.Set; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.Modifier; - /** * LineageContext * @@ -69,33 +63,6 @@ public LineageContext(FlinkChainedProgram flinkChainedProgram, TableEnvironmentI this.tableEnv = tableEnv; } - /** - * Dynamic add getColumnOrigins method to class RelMdColumnOrigins by javassist: - * - * public Set getColumnOrigins(Snapshot rel,RelMetadataQuery mq, int iOutputColumn) { - * return mq.getColumnOrigins(rel.getInput(), iOutputColumn); - * } - */ - static { - try { - ClassPool classPool = ClassPool.getDefault(); - CtClass ctClass = classPool.getCtClass("org.apache.calcite.rel.metadata.RelMdColumnOrigins"); - - CtClass[] parameters = new CtClass[]{classPool.get(Snapshot.class.getName()), - classPool.get(RelMetadataQuery.class.getName()), CtClass.intType - }; - // add method - CtMethod ctMethod = new CtMethod(classPool.get("java.util.Set"), "getColumnOrigins", parameters, ctClass); - ctMethod.setModifiers(Modifier.PUBLIC); - ctMethod.setBody("{return $2.getColumnOrigins($1.getInput(), $3);}"); - ctClass.addMethod(ctMethod); - // load the class - ctClass.toClass(); - } catch (Exception e) { - throw new TableException("Dynamic add getColumnOrigins() method exception.", e); - } - } - public List getLineage(String statement) { // 1. Generate original relNode tree Tuple2 parsed = parseStatement(statement); diff --git a/dlink-client/dlink-client-1.15/src/main/java/com/dlink/utils/LineageContext.java b/dlink-client/dlink-client-1.15/src/main/java/com/dlink/utils/LineageContext.java index 4cf5acb46f..9a6db937bb 100644 --- a/dlink-client/dlink-client-1.15/src/main/java/com/dlink/utils/LineageContext.java +++ b/dlink-client/dlink-client-1.15/src/main/java/com/dlink/utils/LineageContext.java @@ -23,7 +23,6 @@ import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.core.Snapshot; import org.apache.calcite.rel.metadata.RelColumnOrigin; import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.commons.collections.CollectionUtils; @@ -49,11 +48,6 @@ import java.util.List; import java.util.Set; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.Modifier; - /** * LineageContext * @@ -70,33 +64,6 @@ public LineageContext(FlinkChainedProgram flinkChainedProgram, TableEnvironmentI this.tableEnv = tableEnv; } - /** - * Dynamic add getColumnOrigins method to class RelMdColumnOrigins by javassist: - * - * public Set getColumnOrigins(Snapshot rel,RelMetadataQuery mq, int iOutputColumn) { - * return mq.getColumnOrigins(rel.getInput(), iOutputColumn); - * } - */ - static { - try { - ClassPool classPool = ClassPool.getDefault(); - CtClass ctClass = classPool.getCtClass("org.apache.calcite.rel.metadata.RelMdColumnOrigins"); - - CtClass[] parameters = new CtClass[]{classPool.get(Snapshot.class.getName()), - classPool.get(RelMetadataQuery.class.getName()), CtClass.intType - }; - // add method - CtMethod ctMethod = new CtMethod(classPool.get("java.util.Set"), "getColumnOrigins", parameters, ctClass); - ctMethod.setModifiers(Modifier.PUBLIC); - ctMethod.setBody("{return $2.getColumnOrigins($1.getInput(), $3);}"); - ctClass.addMethod(ctMethod); - // load the class - ctClass.toClass(); - } catch (Exception e) { - throw new TableException("Dynamic add getColumnOrigins() method exception.", e); - } - } - public List getLineage(String statement) { // 1. Generate original relNode tree Tuple2 parsed = parseStatement(statement); diff --git a/dlink-client/dlink-client-1.16/src/main/java/com/dlink/utils/LineageContext.java b/dlink-client/dlink-client-1.16/src/main/java/com/dlink/utils/LineageContext.java index 80aaa4bb57..67f5b81153 100644 --- a/dlink-client/dlink-client-1.16/src/main/java/com/dlink/utils/LineageContext.java +++ b/dlink-client/dlink-client-1.16/src/main/java/com/dlink/utils/LineageContext.java @@ -23,7 +23,6 @@ import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.core.Snapshot; import org.apache.calcite.rel.metadata.RelColumnOrigin; import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.commons.collections.CollectionUtils; @@ -49,11 +48,6 @@ import java.util.List; import java.util.Set; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; -import javassist.Modifier; - /** * LineageContext * @@ -70,33 +64,6 @@ public LineageContext(FlinkChainedProgram flinkChainedProgram, TableEnvironmentI this.tableEnv = tableEnv; } - /** - * Dynamic add getColumnOrigins method to class RelMdColumnOrigins by javassist: - * - * public Set getColumnOrigins(Snapshot rel,RelMetadataQuery mq, int iOutputColumn) { - * return mq.getColumnOrigins(rel.getInput(), iOutputColumn); - * } - */ - static { - try { - ClassPool classPool = ClassPool.getDefault(); - CtClass ctClass = classPool.getCtClass("org.apache.calcite.rel.metadata.RelMdColumnOrigins"); - - CtClass[] parameters = new CtClass[]{classPool.get(Snapshot.class.getName()), - classPool.get(RelMetadataQuery.class.getName()), CtClass.intType - }; - // add method - CtMethod ctMethod = new CtMethod(classPool.get("java.util.Set"), "getColumnOrigins", parameters, ctClass); - ctMethod.setModifiers(Modifier.PUBLIC); - ctMethod.setBody("{return $2.getColumnOrigins($1.getInput(), $3);}"); - ctClass.addMethod(ctMethod); - // load the class - ctClass.toClass(); - } catch (Exception e) { - throw new TableException("Dynamic add getColumnOrigins() method exception.", e); - } - } - public List getLineage(String statement) { // 1. Generate original relNode tree Tuple2 parsed = parseStatement(statement); diff --git a/dlink-client/dlink-client-base/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnOrigins.java b/dlink-client/dlink-client-base/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnOrigins.java new file mode 100644 index 0000000000..9a25fc5db3 --- /dev/null +++ b/dlink-client/dlink-client-base/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnOrigins.java @@ -0,0 +1,357 @@ +/* + * + * 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.calcite.rel.metadata; + +import org.apache.calcite.plan.RelOptTable; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.SingleRel; +import org.apache.calcite.rel.core.Aggregate; +import org.apache.calcite.rel.core.AggregateCall; +import org.apache.calcite.rel.core.Calc; +import org.apache.calcite.rel.core.Correlate; +import org.apache.calcite.rel.core.Exchange; +import org.apache.calcite.rel.core.Filter; +import org.apache.calcite.rel.core.Join; +import org.apache.calcite.rel.core.Project; +import org.apache.calcite.rel.core.SetOp; +import org.apache.calcite.rel.core.Snapshot; +import org.apache.calcite.rel.core.Sort; +import org.apache.calcite.rel.core.TableFunctionScan; +import org.apache.calcite.rel.core.TableModify; +import org.apache.calcite.rel.type.RelDataTypeField; +import org.apache.calcite.rex.RexCall; +import org.apache.calcite.rex.RexFieldAccess; +import org.apache.calcite.rex.RexInputRef; +import org.apache.calcite.rex.RexLocalRef; +import org.apache.calcite.rex.RexNode; +import org.apache.calcite.rex.RexShuttle; +import org.apache.calcite.rex.RexVisitor; +import org.apache.calcite.rex.RexVisitorImpl; +import org.apache.calcite.util.BuiltInMethod; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Modified based on calcite's source code org.apache.calcite.rel.metadata.RelMdColumnOrigins + * + * Modification point: + * 1. Support lookup join, add method getColumnOrigins(Snapshot rel, RelMetadataQuery mq, int iOutputColumn) + * 2. Support watermark, add method getColumnOrigins(SingleRel rel,RelMetadataQuery mq, int iOutputColumn) + * 3. Support table function, add method getColumnOrigins(Correlate rel, RelMetadataQuery mq, int iOutputColumn) + * + * + * @description: RelMdColumnOrigins supplies a default implementation of {@link + * RelMetadataQuery#getColumnOrigins} for the standard logical algebra. + * @author: baisong + * @version: 1.0.0 + * @date: 2022/11/24 7:47 PM + */ +public class RelMdColumnOrigins implements MetadataHandler { + + public static final RelMetadataProvider SOURCE = ReflectiveRelMetadataProvider.reflectiveSource( + BuiltInMethod.COLUMN_ORIGIN.method, new RelMdColumnOrigins()); + + // ~ Constructors ----------------------------------------------------------- + + private RelMdColumnOrigins() { + } + + // ~ Methods ---------------------------------------------------------------- + + public MetadataDef getDef() { + return BuiltInMetadata.ColumnOrigin.DEF; + } + + public Set getColumnOrigins(Aggregate rel, + RelMetadataQuery mq, int iOutputColumn) { + if (iOutputColumn < rel.getGroupCount()) { + // get actual index of Group columns. + return mq.getColumnOrigins(rel.getInput(), rel.getGroupSet().asList().get(iOutputColumn)); + } + + // Aggregate columns are derived from input columns + AggregateCall call = rel.getAggCallList().get(iOutputColumn + - rel.getGroupCount()); + + final Set set = new HashSet<>(); + for (Integer iInput : call.getArgList()) { + Set inputSet = mq.getColumnOrigins(rel.getInput(), iInput); + inputSet = createDerivedColumnOrigins(inputSet); + if (inputSet != null) { + set.addAll(inputSet); + } + } + return set; + } + + public Set getColumnOrigins(Join rel, RelMetadataQuery mq, + int iOutputColumn) { + int nLeftColumns = rel.getLeft().getRowType().getFieldList().size(); + Set set; + boolean derived = false; + if (iOutputColumn < nLeftColumns) { + set = mq.getColumnOrigins(rel.getLeft(), iOutputColumn); + if (rel.getJoinType().generatesNullsOnLeft()) { + derived = true; + } + } else { + set = mq.getColumnOrigins(rel.getRight(), iOutputColumn - nLeftColumns); + if (rel.getJoinType().generatesNullsOnRight()) { + derived = true; + } + } + if (derived) { + // nulls are generated due to outer join; that counts + // as derivation + set = createDerivedColumnOrigins(set); + } + return set; + } + + /** + * Support the field blood relationship of table function + */ + public Set getColumnOrigins(Correlate rel, RelMetadataQuery mq, int iOutputColumn) { + + List leftFieldList = rel.getLeft().getRowType().getFieldList(); + + int nLeftColumns = leftFieldList.size(); + Set set; + if (iOutputColumn < nLeftColumns) { + set = mq.getColumnOrigins(rel.getLeft(), iOutputColumn); + } else { + // get the field name of the left table configured in the Table Function on the right + TableFunctionScan tableFunctionScan = (TableFunctionScan) rel.getRight(); + RexCall rexCall = (RexCall) tableFunctionScan.getCall(); + // support only one field in table function + RexFieldAccess rexFieldAccess = (RexFieldAccess) rexCall.operands.get(0); + String fieldName = rexFieldAccess.getField().getName(); + + int leftFieldIndex = 0; + for (int i = 0; i < nLeftColumns; i++) { + if (leftFieldList.get(i).getName().equalsIgnoreCase(fieldName)) { + leftFieldIndex = i; + break; + } + } + /** + * Get the fields from the left table, don't go to + * getColumnOrigins(TableFunctionScan rel,RelMetadataQuery mq, int iOutputColumn), + * otherwise the return is null, and the UDTF field origin cannot be parsed + */ + set = mq.getColumnOrigins(rel.getLeft(), leftFieldIndex); + } + return set; + } + + public Set getColumnOrigins(SetOp rel, + RelMetadataQuery mq, int iOutputColumn) { + final Set set = new HashSet<>(); + for (RelNode input : rel.getInputs()) { + Set inputSet = mq.getColumnOrigins(input, iOutputColumn); + if (inputSet == null) { + return null; + } + set.addAll(inputSet); + } + return set; + } + + /** + * Support the field blood relationship of lookup join + */ + public Set getColumnOrigins(Snapshot rel, + RelMetadataQuery mq, int iOutputColumn) { + return mq.getColumnOrigins(rel.getInput(), iOutputColumn); + } + + /** + * Support the field blood relationship of watermark + */ + public Set getColumnOrigins(SingleRel rel, + RelMetadataQuery mq, int iOutputColumn) { + return mq.getColumnOrigins(rel.getInput(), iOutputColumn); + } + + public Set getColumnOrigins(Project rel, + final RelMetadataQuery mq, int iOutputColumn) { + final RelNode input = rel.getInput(); + RexNode rexNode = rel.getProjects().get(iOutputColumn); + + if (rexNode instanceof RexInputRef) { + // Direct reference: no derivation added. + RexInputRef inputRef = (RexInputRef) rexNode; + return mq.getColumnOrigins(input, inputRef.getIndex()); + } + // Anything else is a derivation, possibly from multiple columns. + final Set set = getMultipleColumns(rexNode, input, mq); + return createDerivedColumnOrigins(set); + } + + public Set getColumnOrigins(Calc rel, + final RelMetadataQuery mq, int iOutputColumn) { + final RelNode input = rel.getInput(); + final RexShuttle rexShuttle = new RexShuttle() { + + @Override + public RexNode visitLocalRef(RexLocalRef localRef) { + return rel.getProgram().expandLocalRef(localRef); + } + }; + final List projects = new ArrayList<>(); + for (RexNode rex : rexShuttle.apply(rel.getProgram().getProjectList())) { + projects.add(rex); + } + final RexNode rexNode = projects.get(iOutputColumn); + if (rexNode instanceof RexInputRef) { + // Direct reference: no derivation added. + RexInputRef inputRef = (RexInputRef) rexNode; + return mq.getColumnOrigins(input, inputRef.getIndex()); + } + // Anything else is a derivation, possibly from multiple columns. + final Set set = getMultipleColumns(rexNode, input, mq); + return createDerivedColumnOrigins(set); + } + + public Set getColumnOrigins(Filter rel, + RelMetadataQuery mq, int iOutputColumn) { + return mq.getColumnOrigins(rel.getInput(), iOutputColumn); + } + + public Set getColumnOrigins(Sort rel, RelMetadataQuery mq, + int iOutputColumn) { + return mq.getColumnOrigins(rel.getInput(), iOutputColumn); + } + + public Set getColumnOrigins(TableModify rel, RelMetadataQuery mq, + int iOutputColumn) { + return mq.getColumnOrigins(rel.getInput(), iOutputColumn); + } + + public Set getColumnOrigins(Exchange rel, + RelMetadataQuery mq, int iOutputColumn) { + return mq.getColumnOrigins(rel.getInput(), iOutputColumn); + } + + public Set getColumnOrigins(TableFunctionScan rel, + RelMetadataQuery mq, int iOutputColumn) { + final Set set = new HashSet<>(); + Set mappings = rel.getColumnMappings(); + if (mappings == null) { + if (rel.getInputs().size() > 0) { + // This is a non-leaf transformation: say we don't + // know about origins, because there are probably + // columns below. + return null; + } else { + // This is a leaf transformation: say there are fer sure no + // column origins. + return set; + } + } + for (RelColumnMapping mapping : mappings) { + if (mapping.iOutputColumn != iOutputColumn) { + continue; + } + final RelNode input = rel.getInputs().get(mapping.iInputRel); + final int column = mapping.iInputColumn; + Set origins = mq.getColumnOrigins(input, column); + if (origins == null) { + return null; + } + if (mapping.derived) { + origins = createDerivedColumnOrigins(origins); + } + set.addAll(origins); + } + return set; + } + + // Catch-all rule when none of the others apply. + public Set getColumnOrigins(RelNode rel, + RelMetadataQuery mq, int iOutputColumn) { + // NOTE jvs 28-Mar-2006: We may get this wrong for a physical table + // expression which supports projections. In that case, + // it's up to the plugin writer to override with the + // correct information. + + if (rel.getInputs().size() > 0) { + // No generic logic available for non-leaf rels. + return null; + } + + final Set set = new HashSet<>(); + + RelOptTable table = rel.getTable(); + if (table == null) { + // Somebody is making column values up out of thin air, like a + // VALUES clause, so we return an empty set. + return set; + } + + // Detect the case where a physical table expression is performing + // projection, and say we don't know instead of making any assumptions. + // (Theoretically we could try to map the projection using column + // names.) This detection assumes the table expression doesn't handle + // rename as well. + if (table.getRowType() != rel.getRowType()) { + return null; + } + + set.add(new RelColumnOrigin(table, iOutputColumn, false)); + return set; + } + + private Set createDerivedColumnOrigins( + Set inputSet) { + if (inputSet == null) { + return null; + } + final Set set = new HashSet<>(); + for (RelColumnOrigin rco : inputSet) { + RelColumnOrigin derived = new RelColumnOrigin( + rco.getOriginTable(), + rco.getOriginColumnOrdinal(), + true); + set.add(derived); + } + return set; + } + + private Set getMultipleColumns(RexNode rexNode, RelNode input, + final RelMetadataQuery mq) { + final Set set = new HashSet<>(); + final RexVisitor visitor = new RexVisitorImpl(true) { + + public Void visitInputRef(RexInputRef inputRef) { + Set inputSet = mq.getColumnOrigins(input, inputRef.getIndex()); + if (inputSet != null) { + set.addAll(inputSet); + } + return null; + } + }; + rexNode.accept(visitor); + return set; + } +}