blob: 4d9abce3a78e6054787157e1cb7cf0d66aa753e8 [file] [log] [blame]
/*
* 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.drill.exec.physical.impl.scan.v3.schema;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.drill.exec.record.metadata.ColumnMetadata;
import org.apache.drill.exec.record.metadata.DynamicColumn;
import org.apache.drill.exec.record.metadata.TupleMetadata;
import org.apache.drill.exec.record.metadata.TupleSchema;
/**
* Enhanced form of a dynamic column which records all information from
* the project list.
*/
public class ProjectedColumn extends DynamicColumn {
/**
* Marker to indicate that that a) the item is an
* array, and b) that all indexes are to be projected.
* Used when seeing both a and a[x].
*/
private static final Set<Integer> ALL_INDEXES = new HashSet<>();
private int refCount = 1;
private int arrayDims;
private Set<Integer> indexes;
private TupleMetadata members;
public ProjectedColumn(String name) {
super(name);
}
protected void bumpRefCount() { refCount++; }
public int refCount() { return refCount; }
public boolean isSimple() {
return !isArray() && !isMap();
}
@Override
public boolean isMap() {
return members != null;
}
public void projectAllElements() {
indexes = ALL_INDEXES;
}
public void becomeArray(int dims) {
arrayDims = dims;
indexes = indexes == null ? new HashSet<>() : indexes;
}
public int arrayDims() { return arrayDims; }
@Override
public boolean isArray() {
return arrayDims > 0;
}
protected void addIndex(int index) {
if (indexes == null) {
indexes = new HashSet<>();
}
if (indexes != ALL_INDEXES) {
indexes.add(index);
}
}
public boolean hasIndexes() {
return isArray() && indexes != ALL_INDEXES;
}
public boolean hasIndex(int index) {
return hasIndexes() && indexes.contains(index);
}
public int maxIndex() {
if (!hasIndexes()) {
return 0;
}
int max = 0;
for (final Integer index : indexes) {
max = Math.max(max, index);
}
return max;
}
public boolean[] indexes() {
if (!hasIndexes()) {
return null;
}
final int max = maxIndex();
final boolean map[] = new boolean[max+1];
for (final Integer index : indexes) {
map[index] = true;
}
return map;
}
public void projectAllMembers() {
if (members == null) {
members = new TupleSchema();
}
members.setProperty(ScanProjectionParser.PROJECTION_TYPE_PROP, ScanProjectionParser.PROJECT_ALL);
}
public TupleMetadata explicitMembers() {
if (members == null) {
members = new TupleSchema();
}
return members;
}
@Override
public TupleMetadata tupleSchema() { return members; }
@Override
protected void appendContents(StringBuilder buf) {
appendArray(buf);
if (isMap()) {
buf.append(" members=").append(members.toString());
}
}
private void appendArray(StringBuilder buf) {
if (isArray()) {
buf.append("[");
if (indexes == ALL_INDEXES) {
buf.append("*");
} else {
List<String> idxs = indexes.stream().sorted().map(i -> Integer.toString(i)).collect(Collectors.toList());
buf.append(String.join(", ", idxs));
}
buf.append("]");
}
}
@Override
public ColumnMetadata copy() {
ProjectedColumn copy = new ProjectedColumn(name);
copy.refCount = refCount;
copy.arrayDims = arrayDims;
copy.indexes = indexes; // Indexes are immutable after parsing
copy.members = members == null ? null : members.copy();
return copy;
}
public String projectString() {
StringBuilder buf = new StringBuilder()
.append(name);
appendArray(buf);
if (isMap()) {
buf.append(" {");
int i = 0;
for (ColumnMetadata child : members) {
if (i++ > 0) {
buf.append(", ");
}
if (child instanceof ProjectedColumn) {
buf.append(((ProjectedColumn) child).projectString());
} else {
buf.append(child.toString());
}
}
buf.append("}");
}
return buf.toString();
}
}