/* * 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.eigenbase.rel; import java.util.List; import org.eigenbase.relopt.*; import org.eigenbase.reltype.*; import org.eigenbase.sql.*; /** * A relational expression which unnests its input's sole column into a * relation. * * <p>Like its inverse operation {@link CollectRel}, UncollectRel is generally * invoked in a nested loop, driven by {@link CorrelatorRel} or similar. */ public class UncollectRel extends SingleRel { //~ Constructors ----------------------------------------------------------- /** * Creates an UncollectRel. * * <p>The row type of the child relational expression must contain precisely * one column, that column must be a multiset of records. * * @param cluster Cluster the relational expression belongs to * @param traitSet Traits * @param child Child relational expression */ public UncollectRel(RelOptCluster cluster, RelTraitSet traitSet, RelNode child) { super(cluster, traitSet, child); assert deriveRowType() != null : "invalid child rowtype"; } /** * Creates an UncollectRel by parsing serialized output. */ public UncollectRel(RelInput input) { this(input.getCluster(), input.getTraitSet(), input.getInput()); } //~ Methods ---------------------------------------------------------------- @Override public final RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) { return copy(traitSet, sole(inputs)); } public RelNode copy(RelTraitSet traitSet, RelNode input) { assert traitSet.containsIfApplicable(Convention.NONE); return new UncollectRel(getCluster(), traitSet, input); } protected RelDataType deriveRowType() { return deriveUncollectRowType(getChild()); } /** * Returns the row type returned by applying the 'UNNEST' operation to a * relational expression. The relational expression must have precisely one * column, whose type must be a multiset of structs. The return type is the * type of that column. */ public static RelDataType deriveUncollectRowType(RelNode rel) { RelDataType inputType = rel.getRowType(); assert inputType.isStruct() : inputType + " is not a struct"; final List<RelDataTypeField> fields = inputType.getFieldList(); assert 1 == fields.size() : "expected 1 field"; RelDataType ret = fields.get(0).getType().getComponentType(); assert null != ret; if (!ret.isStruct()) { // Element type is not a record. It may be a scalar type, say // "INTEGER". Wrap it in a struct type. ret = rel.getCluster().getTypeFactory().builder() .add(SqlUtil.deriveAliasFromOrdinal(0), ret) .build(); } return ret; } } // End UncollectRel.java