You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2021/03/13 07:11:36 UTC

[calcite] 01/04: [CALCITE-4524] Make some fields non-nullable (SqlSelect.selectList, DataContext.getTypeFactory)

This is an automated email from the ASF dual-hosted git repository.

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit 93a2263f7af23be34171a6a1e4f5864a85691650
Author: Julian Hyde <jh...@apache.org>
AuthorDate: Fri Mar 5 09:37:57 2021 -0800

    [CALCITE-4524] Make some fields non-nullable (SqlSelect.selectList, DataContext.getTypeFactory)
    
    In order to make SqlSelect.selectList non-nullable, we had to
    change the flow in RelToSqlConverter, where selectList was
    initially null; now we set it to SqlNodeList.SINGLETON_STAR.
    
    Add class DataContexts, with a few useful implementations of
    interface DataContext. Phase out Schemas.createDataContext.
    
    Resolve some other TODOs relating to nullability.
---
 .../main/java/org/apache/calcite/DataContext.java  |   6 +-
 .../main/java/org/apache/calcite/DataContexts.java | 134 +++++++++++++++++++++
 .../adapter/enumerable/EnumerableWindow.java       |  15 +--
 .../org/apache/calcite/adapter/jdbc/JdbcTable.java |   2 +-
 .../apache/calcite/interpreter/Interpreter.java    |   9 +-
 .../apache/calcite/interpreter/TableScanNode.java  |   5 +-
 .../apache/calcite/jdbc/CalciteConnectionImpl.java |  24 +---
 .../materialize/MaterializationService.java        |  11 +-
 .../ProfilerLatticeStatisticProvider.java          |   4 +-
 .../materialize/SqlLatticeStatisticProvider.java   |   6 +-
 .../org/apache/calcite/model/ModelHandler.java     |   2 +-
 .../calcite/plan/volcano/VolcanoPlanner.java       |   2 +-
 .../org/apache/calcite/rel/core/TableScan.java     |   3 +-
 .../calcite/rel/rel2sql/RelToSqlConverter.java     |  19 ++-
 .../apache/calcite/rel/rel2sql/SqlImplementor.java |  10 +-
 .../apache/calcite/rel/rules/DateRangeRules.java   |   2 +-
 .../apache/calcite/rel/rules/FilterJoinRule.java   |   1 -
 .../calcite/rel/rules/ReduceExpressionsRule.java   |   7 +-
 .../main/java/org/apache/calcite/rex/RexUtil.java  |   6 +-
 .../java/org/apache/calcite/schema/Schemas.java    |  39 +-----
 .../java/org/apache/calcite/sql/SqlSelect.java     |  23 ++--
 .../org/apache/calcite/sql/SqlSelectOperator.java  |  26 +---
 .../calcite/sql/fun/SqlInternalOperators.java      |  10 --
 .../apache/calcite/sql/validate/AggChecker.java    |   3 +-
 .../calcite/sql/validate/SqlValidatorUtil.java     |   4 +-
 .../apache/calcite/sql2rel/SqlToRelConverter.java  |  11 +-
 .../calcite/rel/rel2sql/RelToSqlConverterTest.java |   3 +-
 .../org/apache/calcite/rex/RexExecutorTest.java    |  85 ++++---------
 .../apache/calcite/rex/RexProgramBuilderBase.java  |  43 ++-----
 .../calcite/test/AbstractMaterializedViewTest.java |   5 +-
 .../org/apache/calcite/test/InterpreterTest.java   |   2 +-
 .../apache/calcite/test/LinqFrontJdbcBackTest.java |   3 +-
 .../org/apache/calcite/test/MockRelOptPlanner.java |   4 +-
 .../calcite/test/RexImplicationCheckerTest.java    |   7 +-
 .../calcite/adapter/csv/CsvFilterableTable.java    |   4 +-
 .../calcite/adapter/csv/CsvScannableTable.java     |   4 +-
 .../adapter/csv/CsvStreamScannableTable.java       |   4 +-
 .../calcite/adapter/csv/CsvTranslatableTable.java  |   4 +-
 .../calcite/adapter/file/CsvTranslatableTable.java |   4 +-
 .../calcite/adapter/file/JsonScannableTable.java   |   4 +-
 .../calcite/adapter/os/FilesTableFunction.java     |   2 +-
 .../apache/calcite/adapter/os/PsTableFunction.java |   4 +-
 .../calcite/adapter/os/VmstatTableFunction.java    |   4 +-
 43 files changed, 267 insertions(+), 303 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/DataContext.java b/core/src/main/java/org/apache/calcite/DataContext.java
index f487ff2..a579b0a 100644
--- a/core/src/main/java/org/apache/calcite/DataContext.java
+++ b/core/src/main/java/org/apache/calcite/DataContext.java
@@ -36,6 +36,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Runtime context allowing access to the tables in a database.
+ *
+ * @see DataContexts
  */
 public interface DataContext {
   ParameterExpression ROOT =
@@ -49,12 +51,12 @@ public interface DataContext {
   /**
    * Returns the type factory.
    */
-  @Nullable JavaTypeFactory getTypeFactory();
+  JavaTypeFactory getTypeFactory();
 
   /**
    * Returns the query provider.
    */
-  @Nullable QueryProvider getQueryProvider();
+  QueryProvider getQueryProvider();
 
   /**
    * Returns a context variable.
diff --git a/core/src/main/java/org/apache/calcite/DataContexts.java b/core/src/main/java/org/apache/calcite/DataContexts.java
new file mode 100644
index 0000000..93d4576
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/DataContexts.java
@@ -0,0 +1,134 @@
+/*
+ * 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;
+
+import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.jdbc.CalciteConnection;
+import org.apache.calcite.linq4j.QueryProvider;
+import org.apache.calcite.schema.SchemaPlus;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.function.Function;
+
+import static java.util.Objects.requireNonNull;
+
+/** Utilities for {@link DataContext}. */
+public class DataContexts {
+  private DataContexts() {
+  }
+
+  /** Instance of {@link DataContext} that has no variables. */
+  public static final DataContext EMPTY = new EmptyDataContext();
+
+  /** Returns an instance of {@link DataContext} with the given map. */
+  public static DataContext of(Map<String, ?> map) {
+    return new MapDataContext(map);
+  }
+
+  /** Returns an instance of {@link DataContext} with the given function. */
+  public static DataContext of(Function<String, ? extends @Nullable Object> fn) {
+    return new FunctionDataContext(fn);
+  }
+
+  /** Returns an instance of {@link DataContext} with the given connection
+   * and root schema but no variables. */
+  public static DataContext of(CalciteConnection connection,
+      @Nullable SchemaPlus rootSchema) {
+    return new DataContextImpl(connection, rootSchema, ImmutableMap.of());
+  }
+
+  /** Implementation of {@link DataContext} that has no variables.
+   *
+   * <p>It is {@link Serializable} for Spark's benefit. */
+  private static class EmptyDataContext implements DataContext, Serializable {
+    @Override public @Nullable SchemaPlus getRootSchema() {
+      return null;
+    }
+
+    @Override public JavaTypeFactory getTypeFactory() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override public QueryProvider getQueryProvider() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override public @Nullable Object get(String name) {
+      return null;
+    }
+  }
+
+  /** Implementation of {@link DataContext} backed by a Map.
+   *
+   * <p>Keys and values in the map must not be null. Rather than storing a null
+   * value for a key, remove the key from the map; the effect will be the
+   * same. */
+  private static class MapDataContext extends EmptyDataContext {
+    private final ImmutableMap<String, ?> map;
+
+    MapDataContext(Map<String, ?> map) {
+      this.map = ImmutableMap.copyOf(map);
+    }
+
+    @Override public @Nullable Object get(String name) {
+      return map.get(name);
+    }
+  }
+
+  /** Implementation of {@link DataContext} backed by a Function. */
+  private static class FunctionDataContext extends EmptyDataContext {
+    private final Function<String, ? extends @Nullable Object> fn;
+
+    FunctionDataContext(Function<String, ? extends @Nullable Object> fn) {
+      this.fn = requireNonNull(fn, "fn");
+    }
+
+    @Override public @Nullable Object get(String name) {
+      return fn.apply(name);
+    }
+  }
+
+  /** Implementation of {@link DataContext} backed by a Map. */
+  private static class DataContextImpl extends MapDataContext {
+    private CalciteConnection connection;
+    private @Nullable SchemaPlus rootSchema;
+
+    DataContextImpl(CalciteConnection connection,
+        @Nullable SchemaPlus rootSchema, Map<String, Object> map) {
+      super(map);
+      this.connection = requireNonNull(connection, "connection");
+      this.rootSchema = requireNonNull(rootSchema, "rootSchema");
+    }
+
+    @Override public JavaTypeFactory getTypeFactory() {
+      return connection.getTypeFactory();
+    }
+
+    @Override public @Nullable SchemaPlus getRootSchema() {
+      return rootSchema;
+    }
+
+    @Override public QueryProvider getQueryProvider() {
+      return connection;
+    }
+  }
+}
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
index 2b0fd5c..f6dc230 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java
@@ -318,12 +318,10 @@ public class EnumerableWindow extends Window implements EnumerableRel {
 
       final Expression startUnchecked = builder4.append("start",
           translateBound(translator, i_, row_, minX, maxX, rows_,
-              group, true,
-              inputPhysType, comparator_, keySelector, keyComparator));
+              group, true, inputPhysType, keySelector, keyComparator));
       final Expression endUnchecked = builder4.append("end",
           translateBound(translator, i_, row_, minX, maxX, rows_,
-              group, false,
-              inputPhysType, comparator_, keySelector, keyComparator));
+              group, false, inputPhysType, keySelector, keyComparator));
 
       final Expression startX;
       final Expression endX;
@@ -919,12 +917,9 @@ public class EnumerableWindow extends Window implements EnumerableRel {
   }
 
   private static Expression translateBound(RexToLixTranslator translator,
-          ParameterExpression i_, Expression row_, Expression min_,
-          Expression max_, Expression rows_, Group group,
-          boolean lower,
-          PhysType physType,
-          @SuppressWarnings("unused") Expression rowComparator, // TODO: remove or use
-          @Nullable Expression keySelector, @Nullable Expression keyComparator) {
+      ParameterExpression i_, Expression row_, Expression min_, Expression max_,
+      Expression rows_, Group group, boolean lower, PhysType physType,
+      @Nullable Expression keySelector, @Nullable Expression keyComparator) {
     RexWindowBound bound = lower ? group.lowerBound : group.upperBound;
     if (bound.isUnbounded()) {
       return bound.isPreceding() ? min_ : max_;
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
index 8d3ec00..4151470 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java
@@ -180,7 +180,7 @@ public class JdbcTable extends AbstractQueryableTable
   }
 
   @Override public Enumerable<@Nullable Object[]> scan(DataContext root) {
-    JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory");
+    JavaTypeFactory typeFactory = root.getTypeFactory();
     final SqlString sql = generateSql();
     return ResultSetEnumerable.of(jdbcSchema.getDataSource(), sql.getSql(),
         JdbcUtils.ObjectArrayRowBuilder.factory(fieldClasses(typeFactory)));
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
index 26354b8..fe1f4ab 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.interpreter;
 
 import org.apache.calcite.DataContext;
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.adapter.java.JavaTypeFactory;
 import org.apache.calcite.config.CalciteSystemProperty;
 import org.apache.calcite.linq4j.AbstractEnumerable;
@@ -68,8 +69,6 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.NoSuchElementException;
 
-import static org.apache.calcite.linq4j.Nullness.castNonNull;
-
 import static java.util.Objects.requireNonNull;
 
 /**
@@ -467,10 +466,9 @@ public class Interpreter extends AbstractEnumerable<@Nullable Object[]>
       if (!found) {
         if (p instanceof InterpretableRel) {
           InterpretableRel interpretableRel = (InterpretableRel) p;
-          // TODO: analyze if null is permissible argument for dataContext
           node = interpretableRel.implement(
               new InterpretableRel.InterpreterImplementor(this, null,
-                  castNonNull(null)));
+                  DataContexts.EMPTY));
         } else {
           // Probably need to add a visit(XxxRel) method to CoreCompiler.
           throw new AssertionError("interpreter: no implementation for "
@@ -505,8 +503,7 @@ public class Interpreter extends AbstractEnumerable<@Nullable Object[]>
     }
 
     private JavaTypeFactory getTypeFactory() {
-      return requireNonNull(interpreter.dataContext.getTypeFactory(),
-          () -> "no typeFactory in dataContext");
+      return interpreter.dataContext.getTypeFactory();
     }
 
     @Override public RelDataType combinedRowType(List<RelNode> inputs) {
diff --git a/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java b/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
index 75a5a93..2f552f1 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java
@@ -129,8 +129,9 @@ public class TableScanNode implements Node {
     final Type elementType = queryableTable.getElementType();
     SchemaPlus schema = root.getRootSchema();
     for (String name : Util.skipLast(relOptTable.getQualifiedName())) {
-      requireNonNull(schema, () -> "schema is null while resolving " + name + " for table"
-          + relOptTable.getQualifiedName());
+      requireNonNull(schema, () ->
+          "schema is null while resolving " + name + " for table"
+              + relOptTable.getQualifiedName());
       schema = schema.getSubSchema(name);
     }
     final Enumerable<Row> rowEnumerable;
diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
index a084963..1aab7d9 100644
--- a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
+++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.jdbc;
 
 import org.apache.calcite.DataContext;
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.adapter.java.JavaTypeFactory;
 import org.apache.calcite.avatica.AvaticaConnection;
 import org.apache.calcite.avatica.AvaticaFactory;
@@ -71,7 +72,6 @@ import com.google.common.collect.ImmutableMap;
 
 import org.checkerframework.checker.nullness.qual.Nullable;
 
-import java.io.Serializable;
 import java.lang.reflect.Type;
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -323,7 +323,7 @@ abstract class CalciteConnectionImpl
   public DataContext createDataContext(Map<String, Object> parameterValues,
       @Nullable CalciteSchema rootSchema) {
     if (config().spark()) {
-      return new SlimDataContext();
+      return DataContexts.EMPTY;
     }
     return new DataContextImpl(this, parameterValues, rootSchema);
   }
@@ -572,26 +572,6 @@ abstract class CalciteConnectionImpl
     }
   }
 
-  /** Implementation of {@link DataContext} that has few variables and is
-   * {@link Serializable}. For Spark. */
-  private static class SlimDataContext implements DataContext, Serializable {
-    @Override public @Nullable SchemaPlus getRootSchema() {
-      return null;
-    }
-
-    @Override public @Nullable JavaTypeFactory getTypeFactory() {
-      return null;
-    }
-
-    @Override public @Nullable QueryProvider getQueryProvider() {
-      return null;
-    }
-
-    @Override public @Nullable Object get(String name) {
-      return null;
-    }
-  }
-
   /** Implementation of {@link CalciteServerStatement}. */
   static class CalciteServerStatementImpl
       implements CalciteServerStatement {
diff --git a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
index 912c440..2997d9d 100644
--- a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
+++ b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.materialize;
 
 import org.apache.calcite.DataContext;
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.adapter.clone.CloneSchema;
 import org.apache.calcite.config.CalciteConnectionProperty;
 import org.apache.calcite.jdbc.CalciteConnection;
@@ -393,8 +394,9 @@ public class MaterializationService {
           new AbstractQueryable<Object>() {
             @Override public Enumerator<Object> enumerator() {
               final DataContext dataContext =
-                  Schemas.createDataContext(connection,
-                      requireNonNull(calciteSignature.rootSchema, "rootSchema").plus());
+                  DataContexts.of(connection,
+                      requireNonNull(calciteSignature.rootSchema, "rootSchema")
+                          .plus());
               return calciteSignature.enumerable(dataContext).enumerator();
             }
 
@@ -412,8 +414,9 @@ public class MaterializationService {
 
             @Override public Iterator<Object> iterator() {
               final DataContext dataContext =
-                  Schemas.createDataContext(connection,
-                      requireNonNull(calciteSignature.rootSchema, "rootSchema").plus());
+                  DataContexts.of(connection,
+                      requireNonNull(calciteSignature.rootSchema, "rootSchema")
+                          .plus());
               return calciteSignature.enumerable(dataContext).iterator();
             }
           });
diff --git a/core/src/main/java/org/apache/calcite/materialize/ProfilerLatticeStatisticProvider.java b/core/src/main/java/org/apache/calcite/materialize/ProfilerLatticeStatisticProvider.java
index 2dfdabe..1c13aca 100644
--- a/core/src/main/java/org/apache/calcite/materialize/ProfilerLatticeStatisticProvider.java
+++ b/core/src/main/java/org/apache/calcite/materialize/ProfilerLatticeStatisticProvider.java
@@ -16,12 +16,12 @@
  */
 package org.apache.calcite.materialize;
 
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.linq4j.Enumerable;
 import org.apache.calcite.profile.Profiler;
 import org.apache.calcite.profile.ProfilerImpl;
 import org.apache.calcite.rel.metadata.NullSentinel;
 import org.apache.calcite.schema.ScannableTable;
-import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.impl.MaterializedViewTable;
 import org.apache.calcite.util.ImmutableBitSet;
@@ -67,7 +67,7 @@ class ProfilerLatticeStatisticProvider implements LatticeStatisticProvider {
           ImmutableList.of();
       final Enumerable<List<Comparable>> rows =
           ((ScannableTable) table).scan(
-              Schemas.createDataContext(MaterializedViewTable.MATERIALIZATION_CONNECTION,
+              DataContexts.of(MaterializedViewTable.MATERIALIZATION_CONNECTION,
                   lattice.rootSchema.plus()))
               .select(values -> {
                 for (int i = 0; i < values.length; i++) {
diff --git a/core/src/main/java/org/apache/calcite/materialize/SqlLatticeStatisticProvider.java b/core/src/main/java/org/apache/calcite/materialize/SqlLatticeStatisticProvider.java
index 83b7053..bb42685 100644
--- a/core/src/main/java/org/apache/calcite/materialize/SqlLatticeStatisticProvider.java
+++ b/core/src/main/java/org/apache/calcite/materialize/SqlLatticeStatisticProvider.java
@@ -16,8 +16,8 @@
  */
 package org.apache.calcite.materialize;
 
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.schema.ScannableTable;
-import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.impl.MaterializedViewTable;
 import org.apache.calcite.util.ImmutableBitSet;
@@ -67,8 +67,8 @@ class SqlLatticeStatisticProvider implements LatticeStatisticProvider {
     final @Nullable Object[] values =
         Iterables.getOnlyElement(
             ((ScannableTable) table).scan(
-            Schemas.createDataContext(MaterializedViewTable.MATERIALIZATION_CONNECTION,
-                lattice.rootSchema.plus())));
+                DataContexts.of(MaterializedViewTable.MATERIALIZATION_CONNECTION,
+                    lattice.rootSchema.plus())));
     Number value = (Number) values[0];
     requireNonNull(value, () -> "count(*) produced null in " + sql);
     return value.doubleValue();
diff --git a/core/src/main/java/org/apache/calcite/model/ModelHandler.java b/core/src/main/java/org/apache/calcite/model/ModelHandler.java
index 0475864..acab4b8 100644
--- a/core/src/main/java/org/apache/calcite/model/ModelHandler.java
+++ b/core/src/main/java/org/apache/calcite/model/ModelHandler.java
@@ -447,7 +447,7 @@ public class ModelHandler {
   }
 
   private Pair<? extends @Nullable String, SchemaPlus> nameAndSchema() {
-    return requireNonNull(schemaStack.peek(), "schemaStack.peek()");
+    return schemaStack.getFirst();
   }
 
   private SchemaPlus currentSchema() {
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
index 53dcdc4..14caf5a 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
@@ -1200,7 +1200,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
   /** Returns whether {@code set1} is less popular than {@code set2}
    * (or smaller, or younger). If so, it will be more efficient to merge set1
    * into set2 than set2 into set1. */
-  private boolean isSmaller(RelSet set1, RelSet set2) {
+  private static boolean isSmaller(RelSet set1, RelSet set2) {
     if (set1.parents.size() != set2.parents.size()) {
       return set1.parents.size() < set2.parents.size(); // true if set1 is less popular than set2
     }
diff --git a/core/src/main/java/org/apache/calcite/rel/core/TableScan.java b/core/src/main/java/org/apache/calcite/rel/core/TableScan.java
index de4d195..423cb20 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/TableScan.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/TableScan.java
@@ -44,6 +44,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -68,7 +69,7 @@ public abstract class TableScan
   protected TableScan(RelOptCluster cluster, RelTraitSet traitSet,
       List<RelHint> hints, RelOptTable table) {
     super(cluster, traitSet);
-    this.table = table;
+    this.table = Objects.requireNonNull(table, "table");
     RelOptSchema relOptSchema = table.getRelOptSchema();
     if (relOptSchema != null) {
       cluster.getPlanner().registerSchema(relOptSchema);
diff --git a/core/src/main/java/org/apache/calcite/rel/rel2sql/RelToSqlConverter.java b/core/src/main/java/org/apache/calcite/rel/rel2sql/RelToSqlConverter.java
index b0fd383..918ee29 100644
--- a/core/src/main/java/org/apache/calcite/rel/rel2sql/RelToSqlConverter.java
+++ b/core/src/main/java/org/apache/calcite/rel/rel2sql/RelToSqlConverter.java
@@ -174,11 +174,10 @@ public class RelToSqlConverter extends SqlImplementor
   private static class AliasReplacementShuttle extends SqlShuttle {
     private final String tableAlias;
     private final RelDataType tableType;
-    private final @Nullable SqlNodeList replaceSource;
+    private final SqlNodeList replaceSource;
 
     AliasReplacementShuttle(String tableAlias, RelDataType tableType,
-        @Nullable SqlNodeList replaceSource) {
-      // TODO: should replaceSource be non-nullable?
+        SqlNodeList replaceSource) {
       this.tableAlias = tableAlias;
       this.tableType = tableType;
       this.replaceSource = replaceSource;
@@ -678,10 +677,9 @@ public class RelToSqlConverter extends SqlImplementor
         if (!rename) {
           query = as(query, "t");
         }
-        query = new SqlSelect(POS, null,
-                null, query,
-                createAlwaysFalseCondition(),
-                null, null, null,
+        query =
+            new SqlSelect(POS, null, SqlNodeList.SINGLETON_STAR, query,
+                createAlwaysFalseCondition(), null, null, null,
                 null, null, null, null);
       }
     }
@@ -754,7 +752,8 @@ public class RelToSqlConverter extends SqlImplementor
     final Result x = visitInput(e, 0, Clause.ORDER_BY, Clause.OFFSET,
         Clause.FETCH);
     final Builder builder = x.builder(e);
-    if (stack.size() != 1 && builder.select.getSelectList() == null) {
+    if (stack.size() != 1
+        && builder.select.getSelectList().equals(SqlNodeList.SINGLETON_STAR)) {
       // Generates explicit column names instead of start(*) for
       // non-root order by to avoid ambiguity.
       final List<SqlNode> selectList = Expressions.list();
@@ -993,10 +992,10 @@ public class RelToSqlConverter extends SqlImplementor
     // Convert to table function call, "TABLE($function_name(xxx))"
     SqlNode tableCall = new SqlBasicCall(
         SqlStdOperatorTable.COLLECTION_TABLE,
-        new SqlNode[]{callNode},
+        new SqlNode[] {callNode},
         SqlParserPos.ZERO);
     SqlNode select = new SqlSelect(
-        SqlParserPos.ZERO, null, null, tableCall,
+        SqlParserPos.ZERO, null, SqlNodeList.SINGLETON_STAR, tableCall,
         null, null, null, null, null, null, null, SqlNodeList.EMPTY);
     return result(select, ImmutableList.of(Clause.SELECT), e, null);
   }
diff --git a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
index 4632853..7912359 100644
--- a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
+++ b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
@@ -503,7 +503,7 @@ public abstract class SqlImplementor {
 
     case SELECT:
       final SqlNodeList selectList = ((SqlSelect) node).getSelectList();
-      if (selectList == null) {
+      if (selectList.equals(SqlNodeList.SINGLETON_STAR)) {
         return rowType;
       }
       builder = rel.getCluster().getTypeFactory().builder();
@@ -611,8 +611,8 @@ public abstract class SqlImplementor {
     if (requiresAlias(node)) {
       node = as(node, "t");
     }
-    return new SqlSelect(POS, SqlNodeList.EMPTY, null, node, null, null, null,
-        SqlNodeList.EMPTY, null, null, null, null);
+    return new SqlSelect(POS, SqlNodeList.EMPTY, SqlNodeList.SINGLETON_STAR,
+        node, null, null, null, SqlNodeList.EMPTY, null, null, null, null);
   }
 
   /** Returns whether we need to add an alias if this node is to be the FROM
@@ -1706,7 +1706,7 @@ public abstract class SqlImplementor {
       final Context newContext;
       Map<String, RelDataType> newAliases = null;
       final SqlNodeList selectList = select.getSelectList();
-      if (selectList != null) {
+      if (!selectList.equals(SqlNodeList.SINGLETON_STAR)) {
         final boolean aliasRef = expectedClauses.contains(Clause.HAVING)
             && dialect.getConformance().isHavingAlias();
         newContext = new Context(dialect, selectList.size()) {
@@ -1848,7 +1848,7 @@ public abstract class SqlImplementor {
         Predicate<SqlNode> operandPredicate) {
       if (node instanceof SqlSelect) {
         final SqlNodeList selectList = ((SqlSelect) node).getSelectList();
-        if (selectList != null) {
+        if (!selectList.equals(SqlNodeList.SINGLETON_STAR)) {
           final Set<Integer> aggregatesArgs = new HashSet<>();
           for (AggregateCall aggregateCall : aggregate.getAggCallList()) {
             aggregatesArgs.addAll(aggregateCall.getArgList());
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java b/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java
index b05473e..5912e45 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java
@@ -396,7 +396,7 @@ public abstract class DateRangeRules {
       if (exprs.isEmpty()) {
         return ImmutableList.of(); // a bit more efficient
       }
-      switch (requireNonNull(calls.peek(), "calls.peek()").getKind()) {
+      switch (calls.getFirst().getKind()) {
       case AND:
         return super.visitList(exprs, update);
       default:
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
index 37e2141..7cbabf7 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterJoinRule.java
@@ -208,7 +208,6 @@ public abstract class FilterJoinRule<C extends FilterJoinRule.Config>
             joinType,
             join.isSemiJoinDone());
     call.getPlanner().onCopy(join, newJoinRel);
-    // TODO: review if filter can be nullable here or not
     if (!leftFilters.isEmpty() && filter != null) {
       call.getPlanner().onCopy(filter, leftRel);
     }
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index 8a33c14..eae7cb6 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -1025,14 +1025,15 @@ public abstract class ReduceExpressionsRule<C extends ReduceExpressionsRule.Conf
       //
       // REVIEW zfong 6/13/08 - Are there other expressions where we
       // also need to preserve casts?
-      if (parentCallTypeStack.isEmpty()) {
+      SqlOperator op = parentCallTypeStack.peek();
+      if (op == null) {
         addCasts.add(false);
       } else {
-        addCasts.add(isUdf(parentCallTypeStack.peek()));
+        addCasts.add(isUdf(op));
       }
     }
 
-    private static Boolean isUdf(@SuppressWarnings("unused") @Nullable SqlOperator operator) {
+    private static Boolean isUdf(@SuppressWarnings("unused") SqlOperator operator) {
       // return operator instanceof UserDefinedRoutine
       return false;
     }
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index 54899dc..9d1ff99 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.rex;
 
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.linq4j.function.Predicate1;
 import org.apache.calcite.plan.RelOptPredicateList;
 import org.apache.calcite.plan.RelOptUtil;
@@ -30,7 +31,6 @@ import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeFamily;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexTableInputRef.RelTableRef;
-import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlOperator;
@@ -68,8 +68,6 @@ import java.util.Objects;
 import java.util.Set;
 import java.util.function.Predicate;
 
-import static org.apache.calcite.linq4j.Nullness.castNonNull;
-
 import static java.util.Objects.requireNonNull;
 
 /**
@@ -79,7 +77,7 @@ public class RexUtil {
 
   /** Executor for a bit of constant reduction. The user can pass in another executor. */
   public static final RexExecutor EXECUTOR =
-      new RexExecutorImpl(Schemas.createDataContext(castNonNull(null), null));
+      new RexExecutorImpl(DataContexts.EMPTY);
 
   private RexUtil() {
   }
diff --git a/core/src/main/java/org/apache/calcite/schema/Schemas.java b/core/src/main/java/org/apache/calcite/schema/Schemas.java
index 0a1d5ee..54a82f1 100644
--- a/core/src/main/java/org/apache/calcite/schema/Schemas.java
+++ b/core/src/main/java/org/apache/calcite/schema/Schemas.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.schema;
 
 import org.apache.calcite.DataContext;
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.adapter.enumerable.EnumUtils;
 import org.apache.calcite.adapter.java.JavaTypeFactory;
 import org.apache.calcite.config.CalciteConnectionConfig;
@@ -185,7 +186,7 @@ public final class Schemas {
 
   public static DataContext createDataContext(
       Connection connection, @Nullable SchemaPlus rootSchema) {
-    return new DummyDataContext((CalciteConnection) connection, rootSchema);
+    return DataContexts.of((CalciteConnection) connection, rootSchema);
   }
 
   /** Returns a {@link Queryable}, given a fully-qualified table name. */
@@ -220,8 +221,7 @@ public final class Schemas {
     QueryableTable table = (QueryableTable) requireNonNull(
         schema.getTable(tableName),
         () -> "table " + tableName + " is not found in " + schema);
-    QueryProvider queryProvider = requireNonNull(root.getQueryProvider(),
-        "root.getQueryProvider()");
+    QueryProvider queryProvider = root.getQueryProvider();
     return table.asQueryable(queryProvider, schema, tableName);
   }
 
@@ -245,7 +245,7 @@ public final class Schemas {
    * representing each row as an object array. */
   public static Enumerable<@Nullable Object[]> enumerable(
       final ProjectableFilterableTable table, final DataContext root) {
-    JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory");
+    JavaTypeFactory typeFactory = root.getTypeFactory();
     return table.scan(root, new ArrayList<>(),
         identity(table.getRowType(typeFactory).getFieldCount()));
   }
@@ -374,7 +374,7 @@ public final class Schemas {
       final CalciteConnectionConfig config =
           mutate(connection.config(), propValues);
       return makeContext(config, connection.getTypeFactory(),
-          createDataContext(connection, schema.root().plus()), schema,
+          DataContexts.of(connection, schema.root().plus()), schema,
           schemaPath, objectPath);
     }
   }
@@ -566,35 +566,6 @@ public final class Schemas {
     return new PathImpl(ImmutableList.copyOf(Lists.reverse(list)));
   }
 
-  /** Dummy data context that has no variables. */
-  private static class DummyDataContext implements DataContext {
-    private final CalciteConnection connection;
-    private final @Nullable SchemaPlus rootSchema;
-    private final ImmutableMap<String, Object> map;
-
-    DummyDataContext(CalciteConnection connection, @Nullable SchemaPlus rootSchema) {
-      this.connection = connection;
-      this.rootSchema = rootSchema;
-      this.map = ImmutableMap.of();
-    }
-
-    @Override public @Nullable SchemaPlus getRootSchema() {
-      return rootSchema;
-    }
-
-    @Override public @Nullable JavaTypeFactory getTypeFactory() {
-      return connection.getTypeFactory();
-    }
-
-    @Override public QueryProvider getQueryProvider() {
-      return connection;
-    }
-
-    @Override public @Nullable Object get(String name) {
-      return map.get(name);
-    }
-  }
-
   /** Implementation of {@link Path}. */
   private static class PathImpl
       extends AbstractList<Pair<String, Schema>> implements Path {
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlSelect.java b/core/src/main/java/org/apache/calcite/sql/SqlSelect.java
index d2408bd..4ce27f0 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlSelect.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlSelect.java
@@ -26,7 +26,8 @@ import org.checkerframework.checker.nullness.qual.Nullable;
 import org.checkerframework.dataflow.qual.Pure;
 
 import java.util.List;
-import java.util.Objects;
+
+import static java.util.Objects.requireNonNull;
 
 /**
  * A <code>SqlSelect</code> is a node of a parse tree which represents a select
@@ -42,7 +43,7 @@ public class SqlSelect extends SqlCall {
   public static final int HAVING_OPERAND = 5;
 
   SqlNodeList keywordList;
-  @Nullable SqlNodeList selectList;
+  SqlNodeList selectList;
   @Nullable SqlNode from;
   @Nullable SqlNode where;
   @Nullable SqlNodeList groupBy;
@@ -57,7 +58,7 @@ public class SqlSelect extends SqlCall {
 
   public SqlSelect(SqlParserPos pos,
       @Nullable SqlNodeList keywordList,
-      @Nullable SqlNodeList selectList,
+      SqlNodeList selectList,
       @Nullable SqlNode from,
       @Nullable SqlNode where,
       @Nullable SqlNodeList groupBy,
@@ -68,14 +69,14 @@ public class SqlSelect extends SqlCall {
       @Nullable SqlNode fetch,
       @Nullable SqlNodeList hints) {
     super(pos);
-    this.keywordList = Objects.requireNonNull(keywordList != null
+    this.keywordList = requireNonNull(keywordList != null
         ? keywordList : new SqlNodeList(pos));
-    this.selectList = selectList;
+    this.selectList = requireNonNull(selectList, "selectList");
     this.from = from;
     this.where = where;
     this.groupBy = groupBy;
     this.having = having;
-    this.windowDecls = Objects.requireNonNull(windowDecls != null
+    this.windowDecls = requireNonNull(windowDecls != null
         ? windowDecls : new SqlNodeList(pos));
     this.orderBy = orderBy;
     this.offset = offset;
@@ -102,10 +103,10 @@ public class SqlSelect extends SqlCall {
   @Override public void setOperand(int i, @Nullable SqlNode operand) {
     switch (i) {
     case 0:
-      keywordList = Objects.requireNonNull((SqlNodeList) operand);
+      keywordList = requireNonNull((SqlNodeList) operand);
       break;
     case 1:
-      selectList = (SqlNodeList) operand;
+      selectList = requireNonNull((SqlNodeList) operand);
       break;
     case 2:
       from = operand;
@@ -120,7 +121,7 @@ public class SqlSelect extends SqlCall {
       having = operand;
       break;
     case 6:
-      windowDecls = Objects.requireNonNull((SqlNodeList) operand);
+      windowDecls = requireNonNull((SqlNodeList) operand);
       break;
     case 7:
       orderBy = (SqlNodeList) operand;
@@ -179,11 +180,11 @@ public class SqlSelect extends SqlCall {
   }
 
   @Pure
-  public final @Nullable SqlNodeList getSelectList() {
+  public final SqlNodeList getSelectList() {
     return selectList;
   }
 
-  public void setSelectList(@Nullable SqlNodeList selectList) {
+  public void setSelectList(SqlNodeList selectList) {
     this.selectList = selectList;
   }
 
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java
index 6a4fe85..5902564 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java
@@ -29,6 +29,8 @@ import java.util.List;
 
 import static org.apache.calcite.linq4j.Nullness.castNonNull;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * An operator describing a query. (Not a query itself.)
  *
@@ -68,7 +70,7 @@ public class SqlSelectOperator extends SqlOperator {
     assert functionQualifier == null;
     return new SqlSelect(pos,
         (SqlNodeList) operands[0],
-        (SqlNodeList) operands[1],
+        requireNonNull((SqlNodeList) operands[1], "selectList"),
         operands[2],
         operands[3],
         (SqlNodeList) operands[4],
@@ -83,22 +85,9 @@ public class SqlSelectOperator extends SqlOperator {
   /**
    * Creates a call to the <code>SELECT</code> operator.
    *
-   * @param keywordList List of keywords such DISTINCT and ALL, or null
-   * @param selectList  The SELECT clause, or null if empty
-   * @param fromClause  The FROM clause
-   * @param whereClause The WHERE clause, or null if not present
-   * @param groupBy     The GROUP BY clause, or null if not present
-   * @param having      The HAVING clause, or null if not present
-   * @param windowDecls The WINDOW clause, or null if not present
-   * @param orderBy     The ORDER BY clause, or null if not present
-   * @param offset      Expression for number of rows to discard before
-   *                    returning first row
-   * @param fetch       Expression for number of rows to fetch
-   * @param pos         The parser position, or
-   *                    {@link org.apache.calcite.sql.parser.SqlParserPos#ZERO}
-   *                    if not specified; must not be null.
-   * @return A {@link SqlSelect}, never null
+   * @deprecated Use {@link #createCall(SqlLiteral, SqlParserPos, SqlNode...)}.
    */
+  @Deprecated // to be removed before 2.0
   public SqlSelect createCall(
       SqlNodeList keywordList,
       SqlNodeList selectList,
@@ -161,10 +150,7 @@ public class SqlSelectOperator extends SqlOperator {
       keyword.unparse(writer, 0, 0);
     }
     writer.topN(select.fetch, select.offset);
-    final SqlNodeList selectClause =
-        select.selectList != null
-            ? select.selectList
-            : SqlNodeList.of(SqlIdentifier.star(SqlParserPos.ZERO));
+    final SqlNodeList selectClause = select.selectList;
     writer.list(SqlWriter.FrameTypeEnum.SELECT_LIST, SqlWriter.COMMA,
         selectClause);
 
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlInternalOperators.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlInternalOperators.java
index 0eacee0..ceea8fb 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlInternalOperators.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlInternalOperators.java
@@ -18,8 +18,6 @@ package org.apache.calcite.sql.fun;
 
 import org.apache.calcite.rex.RexCall;
 import org.apache.calcite.sql.SqlCall;
-import org.apache.calcite.sql.SqlFunction;
-import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlInternalOperator;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlNode;
@@ -117,12 +115,4 @@ public abstract class SqlInternalOperators {
       new SqlInternalOperator("SEPARATOR", SqlKind.SEPARATOR, 20, false,
           ReturnTypes.ARG0, InferTypes.RETURN_TYPE, OperandTypes.ANY);
 
-  /** All implementations of {@code SUBSTRING} and {@code SUBSTR} map onto
-   * this. */
-  // TODO:
-  public static final SqlFunction SUBSTRING_INTERNAL =
-      new SqlFunction("$SUBSTRING", SqlKind.OTHER_FUNCTION,
-          ReturnTypes.ARG0_NULLABLE_VARYING, null,
-          OperandTypes.STRING_INTEGER_INTEGER, SqlFunctionCategory.SYSTEM);
-
 }
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java b/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java
index cad01f4..fa04f8c 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/AggChecker.java
@@ -107,8 +107,7 @@ class AggChecker extends SqlBasicVisitor<Void> {
     // it fully-qualified.
     // TODO: It would be better if we always compared fully-qualified
     // to fully-qualified.
-    final SqlQualified fqId = requireNonNull(scopes.peek(), "scopes.peek()")
-        .fullyQualify(id);
+    final SqlQualified fqId = scopes.getFirst().fullyQualify(id);
     if (isGroupExpr(fqId.identifier)) {
       return null;
     }
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
index 4f26761..8138f86 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java
@@ -1185,9 +1185,7 @@ public class SqlValidatorUtil {
         typeFactory,
         SqlValidator.Config.DEFAULT);
     final SqlSelect select = (SqlSelect) validator.validate(select0);
-    SqlNodeList selectList = requireNonNull(
-        select.getSelectList(),
-        () -> "selectList in " + select);
+    SqlNodeList selectList = select.getSelectList();
     assert selectList.size() == 1
         : "Expression " + expr + " should be atom expression";
     final SqlNode node = selectList.get(0);
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index 8d4ac0f..d0beac9 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -1479,7 +1479,7 @@ public class SqlToRelConverter {
     // Check whether query is guaranteed to produce a single value.
     if (query instanceof SqlSelect) {
       SqlSelect select = (SqlSelect) query;
-      SqlNodeList selectList = requireNonNull(select.getSelectList(), "selectList");
+      SqlNodeList selectList = select.getSelectList();
       SqlNodeList groupList = select.getGroup();
 
       if ((selectList.size() == 1)
@@ -3134,7 +3134,6 @@ public class SqlToRelConverter {
     assert bb.root != null : "precondition: child != null";
     SqlNodeList groupList = select.getGroup();
     SqlNodeList selectList = select.getSelectList();
-    assert selectList != null : "selectList must not be null for " + select;
     SqlNode having = select.getHaving();
 
     final AggConverter aggConverter = new AggConverter(bb, select);
@@ -4300,9 +4299,7 @@ public class SqlToRelConverter {
       Blackboard bb,
       SqlSelect select,
       List<SqlNode> orderList) {
-    SqlNodeList selectList = requireNonNull(
-        select.getSelectList(),
-        () -> "null selectList for " + select);
+    SqlNodeList selectList = select.getSelectList();
     selectList = validator().expandStar(selectList, select, false);
 
     replaceSubQueries(bb, selectList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
@@ -5385,9 +5382,7 @@ public class SqlToRelConverter {
 
       // Collect all expressions used in the select list so that aggregate
       // calls can be named correctly.
-      final SqlNodeList selectList = requireNonNull(
-          select.getSelectList(),
-          () -> "selectList must not be null in " + select);
+      final SqlNodeList selectList = select.getSelectList();
       for (int i = 0; i < selectList.size(); i++) {
         SqlNode selectItem = selectList.get(i);
         String name = null;
diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index f1098c6..b7a2585 100644
--- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -5885,7 +5885,8 @@ class RelToSqlConverterTest {
           ImmutableSet.copyOf(librarySet), config, relFn, transforms);
     }
 
-    Sql optimize(final RuleSet ruleSet, final RelOptPlanner relOptPlanner) {
+    Sql optimize(final RuleSet ruleSet,
+        final @Nullable RelOptPlanner relOptPlanner) {
       final List<Function<RelNode, RelNode>> transforms =
           FlatLists.append(this.transforms, r -> {
             Program program = Programs.of(ruleSet);
diff --git a/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java b/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
index e59611c..942d763 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
@@ -17,13 +17,10 @@
 package org.apache.calcite.rex;
 
 import org.apache.calcite.DataContext;
-import org.apache.calcite.adapter.java.JavaTypeFactory;
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.avatica.util.ByteString;
-import org.apache.calcite.linq4j.QueryProvider;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.schema.SchemaPlus;
-import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.sql.SqlBinaryOperator;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlOperator;
@@ -42,7 +39,6 @@ import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
 
-import org.checkerframework.checker.nullness.qual.Nullable;
 import org.hamcrest.Matcher;
 import org.junit.jupiter.api.Test;
 
@@ -65,11 +61,11 @@ import static java.nio.charset.StandardCharsets.UTF_8;
  * Unit test for {@link org.apache.calcite.rex.RexExecutorImpl}.
  */
 class RexExecutorTest {
-  protected void check(final Action action) throws Exception {
+  protected void check(final Action action) {
     Frameworks.withPrepare((cluster, relOptSchema, rootSchema, statement) -> {
       final RexBuilder rexBuilder = cluster.getRexBuilder();
       DataContext dataContext =
-          Schemas.createDataContext(statement.getConnection(), rootSchema);
+          DataContexts.of(statement.getConnection(), rootSchema);
       final RexExecutorImpl executor = new RexExecutorImpl(dataContext);
       action.check(rexBuilder, executor);
       return null;
@@ -78,10 +74,12 @@ class RexExecutorTest {
 
   /** Tests an executor that uses variables stored in a {@link DataContext}.
    * Can change the value of the variable and execute again. */
-  @Test void testVariableExecution() throws Exception {
+  @Test void testVariableExecution() {
     check((rexBuilder, executor) -> {
       Object[] values = new Object[1];
-      final DataContext testContext = new TestDataContext(values);
+      final DataContext testContext =
+          DataContexts.of(name ->
+              name.equals("inputRecord") ? values : fail("unknown: " + name));
       final RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
       final RelDataType varchar =
           typeFactory.createSqlType(SqlTypeName.VARCHAR);
@@ -114,7 +112,7 @@ class RexExecutorTest {
     });
   }
 
-  @Test void testConstant() throws Exception {
+  @Test void testConstant() {
     check((rexBuilder, executor) -> {
       final List<RexNode> reducedValues = new ArrayList<>();
       final RexLiteral ten = rexBuilder.makeExactLiteral(BigDecimal.TEN);
@@ -128,7 +126,7 @@ class RexExecutorTest {
   }
 
   /** Reduces several expressions to constants. */
-  @Test void testConstant2() throws Exception {
+  @Test void testConstant2() {
     // Same as testConstant; 10 -> 10
     checkConstant(10L,
         rexBuilder -> rexBuilder.makeExactLiteral(BigDecimal.TEN));
@@ -156,7 +154,7 @@ class RexExecutorTest {
   }
 
   private void checkConstant(final Object operand,
-      final Function<RexBuilder, RexNode> function) throws Exception {
+      final Function<RexBuilder, RexNode> function) {
     check((rexBuilder, executor) -> {
       final List<RexNode> reducedValues = new ArrayList<>();
       final RexNode expression = function.apply(rexBuilder);
@@ -178,17 +176,17 @@ class RexExecutorTest {
     });
   }
 
-  @Test void testUserFromContext() throws Exception {
+  @Test void testUserFromContext() {
     testContextLiteral(SqlStdOperatorTable.USER,
         DataContext.Variable.USER, "happyCalciteUser");
   }
 
-  @Test void testSystemUserFromContext() throws Exception {
+  @Test void testSystemUserFromContext() {
     testContextLiteral(SqlStdOperatorTable.SYSTEM_USER,
         DataContext.Variable.SYSTEM_USER, "");
   }
 
-  @Test void testTimestampFromContext() throws Exception {
+  @Test void testTimestampFromContext() {
     // CURRENT_TIMESTAMP actually rounds the value to nearest second
     // and that's why we do currentTimeInMillis / 1000 * 1000
     long val = System.currentTimeMillis() / 1000 * 1000;
@@ -212,7 +210,9 @@ class RexExecutorTest {
       final RexBuilder rexBuilder = cluster.getRexBuilder();
       final RexExecutorImpl executor =
           new RexExecutorImpl(
-              new SingleValueDataContext(variable.camelName, value));
+              DataContexts.of(name ->
+                  name.equals(variable.camelName) ? value
+                      : fail("unknown: " + name)));
       try {
         checkConstant(value, builder -> {
           final List<RexNode> output = new ArrayList<>();
@@ -227,7 +227,7 @@ class RexExecutorTest {
     });
   }
 
-  @Test void testSubstring() throws Exception {
+  @Test void testSubstring() {
     check((rexBuilder, executor) -> {
       final List<RexNode> reducedValues = new ArrayList<>();
       final RexLiteral hello =
@@ -253,7 +253,7 @@ class RexExecutorTest {
     });
   }
 
-  @Test void testBinarySubstring() throws Exception {
+  @Test void testBinarySubstring() {
     check((rexBuilder, executor) -> {
       final List<RexNode> reducedValues = new ArrayList<>();
       // hello world! -> 48656c6c6f20776f726c6421
@@ -280,7 +280,7 @@ class RexExecutorTest {
     });
   }
 
-  @Test void testDeterministic1() throws Exception {
+  @Test void testDeterministic1() {
     check((rexBuilder, executor) -> {
       final RexNode plus =
           rexBuilder.makeCall(SqlStdOperatorTable.PLUS,
@@ -290,7 +290,7 @@ class RexExecutorTest {
     });
   }
 
-  @Test void testDeterministic2() throws Exception {
+  @Test void testDeterministic2() {
     check((rexBuilder, executor) -> {
       final RexNode plus =
           rexBuilder.makeCall(PLUS_RANDOM,
@@ -300,7 +300,7 @@ class RexExecutorTest {
     });
   }
 
-  @Test void testDeterministic3() throws Exception {
+  @Test void testDeterministic3() {
     check((rexBuilder, executor) -> {
       final RexNode plus =
           rexBuilder.makeCall(SqlStdOperatorTable.PLUS,
@@ -377,47 +377,4 @@ class RexExecutorTest {
   interface Action {
     void check(RexBuilder rexBuilder, RexExecutorImpl executor);
   }
-
-  /**
-   * ArrayList-based DataContext to check Rex execution.
-   */
-  public static class TestDataContext extends SingleValueDataContext {
-    private TestDataContext(Object[] values) {
-      super("inputRecord", values);
-    }
-  }
-
-  /**
-   * Context that holds a value for a particular context name.
-   */
-  static class SingleValueDataContext implements DataContext {
-    private final String name;
-    private final Object value;
-
-    SingleValueDataContext(String name, Object value) {
-      this.name = name;
-      this.value = value;
-    }
-
-    public SchemaPlus getRootSchema() {
-      throw new RuntimeException("Unsupported");
-    }
-
-    public @Nullable JavaTypeFactory getTypeFactory() {
-      throw new RuntimeException("Unsupported");
-    }
-
-    public @Nullable QueryProvider getQueryProvider() {
-      throw new RuntimeException("Unsupported");
-    }
-
-    public @Nullable Object get(String name) {
-      if (this.name.equals(name)) {
-        return value;
-      } else {
-        fail("Wrong DataContext access");
-        return null;
-      }
-    }
-  }
 }
diff --git a/core/src/test/java/org/apache/calcite/rex/RexProgramBuilderBase.java b/core/src/test/java/org/apache/calcite/rex/RexProgramBuilderBase.java
index 6b25f2c..b6a1470 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexProgramBuilderBase.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexProgramBuilderBase.java
@@ -17,21 +17,19 @@
 package org.apache.calcite.rex;
 
 import org.apache.calcite.DataContext;
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.adapter.java.JavaTypeFactory;
 import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
-import org.apache.calcite.linq4j.QueryProvider;
 import org.apache.calcite.plan.RelOptPredicateList;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
-import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeName;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
-import org.checkerframework.checker.nullness.qual.Nullable;
 import org.junit.jupiter.api.BeforeEach;
 
 import java.math.BigDecimal;
@@ -87,41 +85,16 @@ public abstract class RexProgramBuilderBase {
   // It maps non-nullable type to struct of (10 nullable, 10 non-nullable) fields
   private Map<RelDataType, RexDynamicParam> dynamicParams;
 
-  /**
-   * Dummy data context for test.
-   */
-  private static class DummyTestDataContext implements DataContext {
-    private final ImmutableMap<String, Object> map;
-
-    DummyTestDataContext() {
-      this.map =
-          ImmutableMap.of(
-              Variable.TIME_ZONE.camelName, TimeZone.getTimeZone("America/Los_Angeles"),
-              Variable.CURRENT_TIMESTAMP.camelName, 1311120000000L);
-    }
-
-    public SchemaPlus getRootSchema() {
-      return null;
-    }
-
-    public @Nullable JavaTypeFactory getTypeFactory() {
-      return null;
-    }
-
-    public @Nullable QueryProvider getQueryProvider() {
-      return null;
-    }
-
-    public @Nullable Object get(String name) {
-      return map.get(name);
-    }
-  }
-
   @BeforeEach public void setUp() {
     typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
     rexBuilder = new RexBuilder(typeFactory);
-    executor =
-        new RexExecutorImpl(new DummyTestDataContext());
+    final DataContext dataContext =
+        DataContexts.of(
+            ImmutableMap.of(DataContext.Variable.TIME_ZONE.camelName,
+                TimeZone.getTimeZone("America/Los_Angeles"),
+                DataContext.Variable.CURRENT_TIMESTAMP.camelName,
+                1311120000000L));
+    executor = new RexExecutorImpl(dataContext);
     simplify =
         new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, executor)
             .withParanoid(true);
diff --git a/core/src/test/java/org/apache/calcite/test/AbstractMaterializedViewTest.java b/core/src/test/java/org/apache/calcite/test/AbstractMaterializedViewTest.java
index 0bc7b85..7617813 100644
--- a/core/src/test/java/org/apache/calcite/test/AbstractMaterializedViewTest.java
+++ b/core/src/test/java/org/apache/calcite/test/AbstractMaterializedViewTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.adapter.enumerable.EnumerableTableScan;
 import org.apache.calcite.adapter.java.ReflectiveSchema;
 import org.apache.calcite.config.CalciteConnectionConfig;
@@ -32,7 +33,6 @@ import org.apache.calcite.rel.logical.LogicalTableScan;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rex.RexExecutorImpl;
 import org.apache.calcite.schema.SchemaPlus;
-import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperatorTable;
@@ -136,8 +136,7 @@ public abstract class AbstractMaterializedViewTest {
   private TestConfig build(Sql sql) {
     assert sql != null;
     return Frameworks.withPlanner((cluster, relOptSchema, rootSchema) -> {
-      cluster.getPlanner().setExecutor(
-          new RexExecutorImpl(Schemas.createDataContext(null, null)));
+      cluster.getPlanner().setExecutor(new RexExecutorImpl(DataContexts.EMPTY));
       try {
         final SchemaPlus defaultSchema;
         if (sql.getDefaultSchemaSpec() == null) {
diff --git a/core/src/test/java/org/apache/calcite/test/InterpreterTest.java b/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
index 66852c9..72b40e2 100644
--- a/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/InterpreterTest.java
@@ -71,7 +71,7 @@ class InterpreterTest {
       return rootSchema;
     }
 
-    public @Nullable JavaTypeFactory getTypeFactory() {
+    public JavaTypeFactory getTypeFactory() {
       return (JavaTypeFactory) planner.getTypeFactory();
     }
 
diff --git a/core/src/test/java/org/apache/calcite/test/LinqFrontJdbcBackTest.java b/core/src/test/java/org/apache/calcite/test/LinqFrontJdbcBackTest.java
index f0ab387..ade42ec 100644
--- a/core/src/test/java/org/apache/calcite/test/LinqFrontJdbcBackTest.java
+++ b/core/src/test/java/org/apache/calcite/test/LinqFrontJdbcBackTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.jdbc.CalciteConnection;
 import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.linq4j.tree.ParameterExpression;
@@ -42,7 +43,7 @@ class LinqFrontJdbcBackTest {
     ParameterExpression c =
         Expressions.parameter(JdbcTest.Customer.class, "c");
     String s =
-        Schemas.queryable(Schemas.createDataContext(connection, rootSchema),
+        Schemas.queryable(DataContexts.of(calciteConnection, rootSchema),
             rootSchema.getSubSchema("foodmart"),
             JdbcTest.Customer.class, "customer")
             .where(
diff --git a/core/src/test/java/org/apache/calcite/test/MockRelOptPlanner.java b/core/src/test/java/org/apache/calcite/test/MockRelOptPlanner.java
index a1b0e84..d2a7a52 100644
--- a/core/src/test/java/org/apache/calcite/test/MockRelOptPlanner.java
+++ b/core/src/test/java/org/apache/calcite/test/MockRelOptPlanner.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.plan.AbstractRelOptPlanner;
 import org.apache.calcite.plan.Context;
 import org.apache.calcite.plan.RelHintsPropagator;
@@ -27,7 +28,6 @@ import org.apache.calcite.plan.RelOptRuleOperand;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rex.RexExecutorImpl;
-import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.util.Pair;
 
 import com.google.common.collect.ImmutableList;
@@ -59,7 +59,7 @@ public class MockRelOptPlanner extends AbstractRelOptPlanner {
   /** Creates MockRelOptPlanner. */
   public MockRelOptPlanner(Context context) {
     super(RelOptCostImpl.FACTORY, context);
-    setExecutor(new RexExecutorImpl(Schemas.createDataContext(null, null)));
+    setExecutor(new RexExecutorImpl(DataContexts.EMPTY));
   }
 
   // implement RelOptPlanner
diff --git a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
index 4241444..c17d2ae 100644
--- a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.DataContexts;
 import org.apache.calcite.avatica.util.TimeUnitRange;
 import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
 import org.apache.calcite.plan.RelOptPredicateList;
@@ -31,7 +32,6 @@ import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexSimplify;
 import org.apache.calcite.rex.RexUnknownAs;
-import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.sql.SqlCollation;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
@@ -259,7 +259,7 @@ public class RexImplicationCheckerTest {
     f.checkImplies(f.and(node3, node4), f.and(node5, node6));
   }
 
-  /** Similar to {@link MaterializationTest#testAlias()}:
+  /** Similar to {@link MaterializedViewSubstitutionVisitorTest#testAlias()}:
    * {@code x > 1 OR (y > 2 AND z > 4)}
    * implies
    * {@code (y > 3 AND z > 5)}. */
@@ -533,8 +533,7 @@ public class RexImplicationCheckerTest {
       executor = Frameworks.withPrepare(
           (cluster, relOptSchema, rootSchema, statement) ->
               new RexExecutorImpl(
-                  Schemas.createDataContext(statement.getConnection(),
-                      rootSchema)));
+                  DataContexts.of(statement.getConnection(), rootSchema)));
       simplify =
           new RexSimplify(rexBuilder, RelOptPredicateList.EMPTY, executor)
               .withParanoid(true);
diff --git a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvFilterableTable.java b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvFilterableTable.java
index efd18d6..c61a04c 100644
--- a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvFilterableTable.java
+++ b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvFilterableTable.java
@@ -38,8 +38,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import static java.util.Objects.requireNonNull;
-
 /**
  * Table based on a CSV file that can implement simple filtering.
  *
@@ -58,7 +56,7 @@ public class CsvFilterableTable extends CsvTable
   }
 
   @Override public Enumerable<@Nullable Object[]> scan(DataContext root, List<RexNode> filters) {
-    JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "typeFactory");
+    JavaTypeFactory typeFactory = root.getTypeFactory();
     final List<CsvFieldType> fieldTypes = getFieldTypes(typeFactory);
     final @Nullable String[] filterValues = new String[fieldTypes.size()];
     filters.removeIf(filter -> addFilter(filter, filterValues));
diff --git a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvScannableTable.java b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvScannableTable.java
index 95a4660..dd24e21 100644
--- a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvScannableTable.java
+++ b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvScannableTable.java
@@ -33,8 +33,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import static java.util.Objects.requireNonNull;
-
 /**
  * Table based on a CSV file.
  *
@@ -53,7 +51,7 @@ public class CsvScannableTable extends CsvTable
   }
 
   @Override public Enumerable<@Nullable Object[]> scan(DataContext root) {
-    JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory");
+    JavaTypeFactory typeFactory = root.getTypeFactory();
     final List<CsvFieldType> fieldTypes = getFieldTypes(typeFactory);
     final List<Integer> fields = ImmutableIntList.identity(fieldTypes.size());
     final AtomicBoolean cancelFlag = DataContext.Variable.CANCEL_FLAG.get(root);
diff --git a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvStreamScannableTable.java b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvStreamScannableTable.java
index a665daa..2c01cd4 100644
--- a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvStreamScannableTable.java
+++ b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvStreamScannableTable.java
@@ -35,8 +35,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import static java.util.Objects.requireNonNull;
-
 /**
  * Table based on a CSV file.
  *
@@ -59,7 +57,7 @@ public class CsvStreamScannableTable extends CsvScannableTable
   }
 
   @Override public Enumerable<@Nullable Object[]> scan(DataContext root) {
-    JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory");
+    JavaTypeFactory typeFactory = root.getTypeFactory();
     final List<CsvFieldType> fieldTypes = getFieldTypes(typeFactory);
     final List<Integer> fields = ImmutableIntList.identity(fieldTypes.size());
     final AtomicBoolean cancelFlag = DataContext.Variable.CANCEL_FLAG.get(root);
diff --git a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTranslatableTable.java b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTranslatableTable.java
index c83125c..51cc683 100644
--- a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTranslatableTable.java
+++ b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTranslatableTable.java
@@ -38,8 +38,6 @@ import org.apache.calcite.util.Source;
 import java.lang.reflect.Type;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import static java.util.Objects.requireNonNull;
-
 /**
  * Table based on a CSV file.
  */
@@ -61,7 +59,7 @@ public class CsvTranslatableTable extends CsvTable
     final AtomicBoolean cancelFlag = DataContext.Variable.CANCEL_FLAG.get(root);
     return new AbstractEnumerable<Object>() {
       @Override public Enumerator<Object> enumerator() {
-        JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory");
+        JavaTypeFactory typeFactory = root.getTypeFactory();
         return new CsvEnumerator<>(
             source,
             cancelFlag,
diff --git a/file/src/main/java/org/apache/calcite/adapter/file/CsvTranslatableTable.java b/file/src/main/java/org/apache/calcite/adapter/file/CsvTranslatableTable.java
index c564df7..e927a58 100644
--- a/file/src/main/java/org/apache/calcite/adapter/file/CsvTranslatableTable.java
+++ b/file/src/main/java/org/apache/calcite/adapter/file/CsvTranslatableTable.java
@@ -37,8 +37,6 @@ import org.apache.calcite.util.Source;
 import java.lang.reflect.Type;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import static java.util.Objects.requireNonNull;
-
 /**
  * Table based on a CSV file.
  *
@@ -63,7 +61,7 @@ public class CsvTranslatableTable extends CsvTable
     final AtomicBoolean cancelFlag = DataContext.Variable.CANCEL_FLAG.get(root);
     return new AbstractEnumerable<Object>() {
       @Override public Enumerator<Object> enumerator() {
-        JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory");
+        JavaTypeFactory typeFactory = root.getTypeFactory();
         return new CsvEnumerator<>(source, cancelFlag,
             getFieldTypes(typeFactory), ImmutableIntList.of(fields));
       }
diff --git a/file/src/main/java/org/apache/calcite/adapter/file/JsonScannableTable.java b/file/src/main/java/org/apache/calcite/adapter/file/JsonScannableTable.java
index 757b464..8f9d2bd 100644
--- a/file/src/main/java/org/apache/calcite/adapter/file/JsonScannableTable.java
+++ b/file/src/main/java/org/apache/calcite/adapter/file/JsonScannableTable.java
@@ -26,8 +26,6 @@ import org.apache.calcite.util.Source;
 
 import org.checkerframework.checker.nullness.qual.Nullable;
 
-import static java.util.Objects.requireNonNull;
-
 /**
  * Table based on a JSON file.
  *
@@ -50,7 +48,7 @@ public class JsonScannableTable extends JsonTable
   @Override public Enumerable<@Nullable Object[]> scan(DataContext root) {
     return new AbstractEnumerable<@Nullable Object[]>() {
       @Override public Enumerator<@Nullable Object[]> enumerator() {
-        JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory");
+        JavaTypeFactory typeFactory = root.getTypeFactory();
         return new JsonEnumerator(getDataList(typeFactory));
       }
     };
diff --git a/plus/src/main/java/org/apache/calcite/adapter/os/FilesTableFunction.java b/plus/src/main/java/org/apache/calcite/adapter/os/FilesTableFunction.java
index 5efb150..c09c9f5 100644
--- a/plus/src/main/java/org/apache/calcite/adapter/os/FilesTableFunction.java
+++ b/plus/src/main/java/org/apache/calcite/adapter/os/FilesTableFunction.java
@@ -150,7 +150,7 @@ public class FilesTableFunction {
       }
 
       @Override public Enumerable<@Nullable Object[]> scan(DataContext root) {
-        JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory");
+        JavaTypeFactory typeFactory = root.getTypeFactory();
         final RelDataType rowType = getRowType(typeFactory);
         final List<String> fieldNames =
             ImmutableList.copyOf(rowType.getFieldNames());
diff --git a/plus/src/main/java/org/apache/calcite/adapter/os/PsTableFunction.java b/plus/src/main/java/org/apache/calcite/adapter/os/PsTableFunction.java
index 49102b5..d84f836 100644
--- a/plus/src/main/java/org/apache/calcite/adapter/os/PsTableFunction.java
+++ b/plus/src/main/java/org/apache/calcite/adapter/os/PsTableFunction.java
@@ -42,8 +42,6 @@ import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import static java.util.Objects.requireNonNull;
-
 /**
  * Table function that executes the OS "ps" command
  * to list processes.
@@ -59,7 +57,7 @@ public class PsTableFunction {
   public static ScannableTable eval(boolean b) {
     return new ScannableTable() {
       @Override public Enumerable<@Nullable Object[]> scan(DataContext root) {
-        JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory");
+        JavaTypeFactory typeFactory = root.getTypeFactory();
         final RelDataType rowType = getRowType(typeFactory);
         final List<String> fieldNames =
             ImmutableList.copyOf(rowType.getFieldNames());
diff --git a/plus/src/main/java/org/apache/calcite/adapter/os/VmstatTableFunction.java b/plus/src/main/java/org/apache/calcite/adapter/os/VmstatTableFunction.java
index 6b800f6..ecfda06 100644
--- a/plus/src/main/java/org/apache/calcite/adapter/os/VmstatTableFunction.java
+++ b/plus/src/main/java/org/apache/calcite/adapter/os/VmstatTableFunction.java
@@ -39,8 +39,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
 
 import java.util.List;
 
-import static java.util.Objects.requireNonNull;
-
 /**
  * Table function that executes the OS "vmstat" command
  * to share memory statistics.
@@ -52,7 +50,7 @@ public class VmstatTableFunction {
   public static ScannableTable eval(boolean b) {
     return new ScannableTable() {
       @Override public Enumerable<@Nullable Object[]> scan(DataContext root) {
-        JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory");
+        JavaTypeFactory typeFactory = root.getTypeFactory();
         final RelDataType rowType = getRowType(typeFactory);
         final List<String> fieldNames =
             ImmutableList.copyOf(rowType.getFieldNames());