blob: dfd3d7260607f6274f6a208b3b8600a18c9b2e2f [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.druid.sql.calcite.table;
import com.google.common.base.Preconditions;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.logical.LogicalTableScan;
import org.apache.druid.catalog.model.facade.DatasourceFacade;
import org.apache.druid.query.DataSource;
import org.apache.druid.query.TableDataSource;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.column.RowSignature;
import org.apache.druid.segment.metadata.DataSourceInformation;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* Represents a SQL table that models a Druid datasource.
* <p>
* Once the catalog code is merged, this class will combine physical information
* from the segment cache with logical information from the catalog to produce
* the SQL-user's view of the table. The resulting merged view is used to plan
* queries and is the source of table information in the {@code INFORMATION_SCHEMA}.
*/
public class DatasourceTable extends DruidTable
{
/**
* The physical metadata for a datasource, derived from the list of segments
* published in the Coordinator. Used only for datasources, since only
* datasources are computed from segments.
*/
public static class PhysicalDatasourceMetadata extends DataSourceInformation implements DatasourceMetadata
{
private final TableDataSource tableDataSource;
private final boolean joinable;
private final boolean broadcast;
public PhysicalDatasourceMetadata(
final TableDataSource tableDataSource,
final RowSignature rowSignature,
final boolean isJoinable,
final boolean isBroadcast
)
{
super(tableDataSource.getName(), rowSignature);
this.tableDataSource = Preconditions.checkNotNull(tableDataSource, "dataSource");
this.joinable = isJoinable;
this.broadcast = isBroadcast;
}
@Override
public TableDataSource dataSource()
{
return tableDataSource;
}
@Override
public boolean isJoinable()
{
return joinable;
}
@Override
public boolean isBroadcast()
{
return broadcast;
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
PhysicalDatasourceMetadata that = (PhysicalDatasourceMetadata) o;
return Objects.equals(tableDataSource, that.tableDataSource);
}
@Override
public int hashCode()
{
int result = tableDataSource != null ? tableDataSource.hashCode() : 0;
result = 31 * result + super.hashCode();
return result;
}
@Override
public String toString()
{
return "DatasourceMetadata{" +
"dataSource=" + tableDataSource +
", rowSignature=" + getRowSignature() +
'}';
}
}
public static class EffectiveColumnMetadata
{
protected final String name;
protected final ColumnType type;
public EffectiveColumnMetadata(String name, ColumnType type)
{
this.name = name;
this.type = type;
}
public String name()
{
return name;
}
public ColumnType druidType()
{
return type;
}
public static EffectiveColumnMetadata fromPhysical(String name, ColumnType type)
{
return new EffectiveColumnMetadata(name, type);
}
@Override
public String toString()
{
return "Column{" +
"name=" + name +
", type=" + type.asTypeString() +
"}";
}
}
public static class EffectiveMetadata
{
private final DatasourceFacade catalogMetadata;
private final boolean isEmpty;
private final Map<String, EffectiveColumnMetadata> columns;
public EffectiveMetadata(
final DatasourceFacade catalogMetadata,
final Map<String, EffectiveColumnMetadata> columns,
final boolean isEmpty
)
{
this.catalogMetadata = catalogMetadata;
this.isEmpty = isEmpty;
this.columns = columns;
}
public static Map<String, EffectiveColumnMetadata> toEffectiveColumns(RowSignature rowSignature)
{
Map<String, EffectiveColumnMetadata> columns = new HashMap<>();
for (int i = 0; i < rowSignature.size(); i++) {
String colName = rowSignature.getColumnName(i);
ColumnType colType = rowSignature.getColumnType(i).get();
EffectiveColumnMetadata colMetadata = EffectiveColumnMetadata.fromPhysical(colName, colType);
columns.put(colName, colMetadata);
}
return columns;
}
public static EffectiveMetadata of(RowSignature rowSignature)
{
return new EffectiveMetadata(null, toEffectiveColumns(rowSignature), false);
}
public DatasourceFacade catalogMetadata()
{
return catalogMetadata;
}
public EffectiveColumnMetadata column(String name)
{
return columns.get(name);
}
public boolean isEmpty()
{
return isEmpty;
}
@Override
public String toString()
{
return getClass().getSimpleName() + "{" +
"empty=" + isEmpty +
", columns=" + columns +
"}";
}
}
private final DatasourceMetadata physicalMetadata;
private final EffectiveMetadata effectiveMetadata;
public DatasourceTable(
final PhysicalDatasourceMetadata physicalMetadata
)
{
this(
physicalMetadata.getRowSignature(),
physicalMetadata,
EffectiveMetadata.of(physicalMetadata.getRowSignature())
);
}
public DatasourceTable(
final RowSignature rowSignature,
final DatasourceMetadata physicalMetadata,
final EffectiveMetadata effectiveMetadata
)
{
super(rowSignature);
this.physicalMetadata = physicalMetadata;
this.effectiveMetadata = effectiveMetadata;
}
@Override
public DataSource getDataSource()
{
return physicalMetadata.dataSource();
}
@Override
public boolean isJoinable()
{
return physicalMetadata.isJoinable();
}
@Override
public boolean isBroadcast()
{
return physicalMetadata.isBroadcast();
}
public EffectiveMetadata effectiveMetadata()
{
return effectiveMetadata;
}
@Override
public RelNode toRel(final RelOptTable.ToRelContext context, final RelOptTable table)
{
return LogicalTableScan.create(context.getCluster(), table, context.getTableHints());
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DatasourceTable that = (DatasourceTable) o;
if (!Objects.equals(physicalMetadata, that.physicalMetadata)) {
return false;
}
return Objects.equals(getRowSignature(), that.getRowSignature());
}
@Override
public int hashCode()
{
return physicalMetadata.hashCode();
}
@Override
public String toString()
{
// Don't include the row signature: it is the same as in
// effectiveMetadata.
return "DruidTable{physicalMetadata=" +
(physicalMetadata == null ? "null" : physicalMetadata.toString()) +
", effectiveMetadata=" + effectiveMetadata +
'}';
}
}