content: /*
   * 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.
   *
   * @deprecated As of 1.30.0, if you need to know how tables in a plan are accessed you are
   * encouraged to implement your own logic (using a RelNode visitor or other). The class is not used
   * anywhere in the project and remains untested thus it is deprecated.
   */
  @Deprecated // to be removed before 2.0
  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);
      }
    }
  }
  