blob: 98a4fa52abb055879e597ac6b53c55bc851d0189 [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.calcite.plan;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelVisitor;
import org.apache.calcite.rel.core.TableModify;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
// TODO jvs 9-Mar-2006: move this class to another package; it
// doesn't really belong here. Also, use a proper class for table
// names instead of List<String>.
/**
* <code>TableAccessMap</code> represents the tables accessed by a query plan,
* with READ/WRITE information.
*/
public class TableAccessMap {
//~ Enums ------------------------------------------------------------------
/** Access mode. */
public enum Mode {
/**
* Table is not accessed at all.
*/
NO_ACCESS,
/**
* Table is accessed for read only.
*/
READ_ACCESS,
/**
* Table is accessed for write only.
*/
WRITE_ACCESS,
/**
* Table is accessed for both read and write.
*/
READWRITE_ACCESS
}
//~ Instance fields --------------------------------------------------------
private final Map<List<String>, Mode> accessMap;
//~ Constructors -----------------------------------------------------------
/**
* Constructs a permanently empty TableAccessMap.
*/
public TableAccessMap() {
accessMap = Collections.EMPTY_MAP;
}
/**
* Constructs a TableAccessMap for all tables accessed by a RelNode and its
* descendants.
*
* @param rel the RelNode for which to build the map
*/
public TableAccessMap(RelNode rel) {
// NOTE jvs 9-Mar-2006: This method must NOT retain a reference to the
// input rel, because we use it for cached statements, and we don't
// want to retain any rel references after preparation completes.
accessMap = new HashMap<>();
RelOptUtil.go(
new TableRelVisitor(),
rel);
}
/**
* Constructs a TableAccessMap for a single table.
*
* @param table fully qualified name of the table, represented as a list
* @param mode access mode for the table
*/
public TableAccessMap(List<String> table, Mode mode) {
accessMap = new HashMap<>();
accessMap.put(table, mode);
}
//~ Methods ----------------------------------------------------------------
/**
* Returns a set of qualified names for all tables accessed.
*/
@SuppressWarnings("return.type.incompatible")
public Set<List<String>> getTablesAccessed() {
return accessMap.keySet();
}
/**
* Determines whether a table is accessed at all.
*
* @param tableName qualified name of the table of interest
* @return true if table is accessed
*/
public boolean isTableAccessed(List<String> tableName) {
return accessMap.containsKey(tableName);
}
/**
* Determines whether a table is accessed for read.
*
* @param tableName qualified name of the table of interest
* @return true if table is accessed for read
*/
public boolean isTableAccessedForRead(List<String> tableName) {
Mode mode = getTableAccessMode(tableName);
return (mode == Mode.READ_ACCESS) || (mode == Mode.READWRITE_ACCESS);
}
/**
* Determines whether a table is accessed for write.
*
* @param tableName qualified name of the table of interest
* @return true if table is accessed for write
*/
public boolean isTableAccessedForWrite(List<String> tableName) {
Mode mode = getTableAccessMode(tableName);
return (mode == Mode.WRITE_ACCESS) || (mode == Mode.READWRITE_ACCESS);
}
/**
* Determines the access mode of a table.
*
* @param tableName qualified name of the table of interest
* @return access mode
*/
public Mode getTableAccessMode(List<String> tableName) {
Mode mode = accessMap.get(tableName);
if (mode == null) {
return Mode.NO_ACCESS;
}
return mode;
}
/**
* Constructs a qualified name for an optimizer table reference.
*
* @param table table of interest
* @return qualified name
*/
public List<String> getQualifiedName(RelOptTable table) {
return table.getQualifiedName();
}
//~ Inner Classes ----------------------------------------------------------
/** Visitor that finds all tables in a tree. */
private class TableRelVisitor extends RelVisitor {
@Override public void visit(
RelNode p,
int ordinal,
@Nullable RelNode parent) {
super.visit(p, ordinal, parent);
RelOptTable table = p.getTable();
if (table == null) {
return;
}
Mode newAccess;
// FIXME jvs 1-Feb-2006: Don't rely on object type here;
// eventually someone is going to write a rule which transforms
// to something which doesn't inherit TableModify,
// and this will break. Need to make this explicit in
// the RelNode interface.
if (p instanceof TableModify) {
newAccess = Mode.WRITE_ACCESS;
} else {
newAccess = Mode.READ_ACCESS;
}
List<String> key = getQualifiedName(table);
Mode oldAccess = accessMap.get(key);
if ((oldAccess != null) && (oldAccess != newAccess)) {
newAccess = Mode.READWRITE_ACCESS;
}
accessMap.put(key, newAccess);
}
}
}