diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java index b7eae2023a88..1a62e9d380fa 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableLimit.java @@ -35,12 +35,14 @@ import org.apache.calcite.rex.RexNode; import org.apache.calcite.util.BuiltInMethod; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** Relational expression that applies a limit and/or offset to its input. */ public class EnumerableLimit extends SingleRel implements EnumerableRel { - public final RexNode offset; - public final RexNode fetch; + public final @Nullable RexNode offset; + public final @Nullable RexNode fetch; /** Creates an EnumerableLimit. * @@ -49,8 +51,8 @@ public EnumerableLimit( RelOptCluster cluster, RelTraitSet traitSet, RelNode input, - RexNode offset, - RexNode fetch) { + @Nullable RexNode offset, + @Nullable RexNode fetch) { super(cluster, traitSet, input); this.offset = offset; this.fetch = fetch; @@ -59,8 +61,8 @@ public EnumerableLimit( } /** Creates an EnumerableLimit. */ - public static EnumerableLimit create(final RelNode input, RexNode offset, - RexNode fetch) { + public static EnumerableLimit create(final RelNode input, @Nullable RexNode offset, + @Nullable RexNode fetch) { final RelOptCluster cluster = input.getCluster(); final RelMetadataQuery mq = cluster.getMetadataQuery(); final RelTraitSet traitSet = diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableFunctionScan.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableFunctionScan.java index 947d141eb1d8..e62589118678 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableFunctionScan.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableFunctionScan.java @@ -50,7 +50,7 @@ public class EnumerableTableFunctionScan extends TableFunctionScan public EnumerableTableFunctionScan(RelOptCluster cluster, RelTraitSet traits, List inputs, @Nullable Type elementType, - @Nullable RelDataType rowType, RexNode call, + RelDataType rowType, RexNode call, @Nullable Set columnMappings) { super(cluster, traits, inputs, call, elementType, rowType, columnMappings); @@ -61,7 +61,7 @@ public EnumerableTableFunctionScan(RelOptCluster cluster, List inputs, RexNode rexCall, @Nullable Type elementType, - @Nullable RelDataType rowType, + RelDataType rowType, @Nullable Set columnMappings) { return new EnumerableTableFunctionScan(getCluster(), traitSet, inputs, elementType, rowType, rexCall, columnMappings); diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java index d65fa1e0a795..0925aae77465 100644 --- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java +++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java @@ -19,7 +19,6 @@ import org.apache.calcite.avatica.AvaticaUtils; import org.apache.calcite.avatica.MetaImpl; import org.apache.calcite.avatica.SqlType; -import org.apache.calcite.linq4j.Nullness; import org.apache.calcite.linq4j.function.Experimental; import org.apache.calcite.linq4j.tree.Expression; import org.apache.calcite.rel.type.RelDataType; @@ -85,7 +84,7 @@ public class JdbcSchema implements Schema { private final boolean snapshot; @Experimental - public static final ThreadLocal THREAD_METADATA = new ThreadLocal<>(); + public static final ThreadLocal<@Nullable Foo> THREAD_METADATA = new ThreadLocal<>(); private static final Ordering> VERSION_ORDERING = Ordering.natural().lexicographical(); diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java index 8d82e30b1658..d3da6220617f 100644 --- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java +++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcToEnumerableConverter.java @@ -24,7 +24,6 @@ import org.apache.calcite.adapter.enumerable.PhysTypeImpl; import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.config.CalciteSystemProperty; -import org.apache.calcite.linq4j.Nullness; import org.apache.calcite.linq4j.tree.BlockBuilder; import org.apache.calcite.linq4j.tree.ConstantExpression; import org.apache.calcite.linq4j.tree.Expression; @@ -41,7 +40,6 @@ import org.apache.calcite.rel.convert.ConverterImpl; import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.rel.type.RelDataType; -import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.runtime.Hook; import org.apache.calcite.runtime.SqlFunctions; import org.apache.calcite.schema.Schemas; diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java index fde7bfefbc90..bafda51bbe7c 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java @@ -68,7 +68,7 @@ */ public interface CalcitePrepare { Function0 DEFAULT_FACTORY = CalcitePrepareImpl::new; - ThreadLocal> THREAD_CONTEXT_STACK = + ThreadLocal<@Nullable Deque> THREAD_CONTEXT_STACK = ThreadLocal.withInitial(ArrayDeque::new); ParseResult parse(Context context, String sql); @@ -189,7 +189,7 @@ private static SparkHandler createHandler() { } public static void push(Context context) { - final Deque stack = THREAD_CONTEXT_STACK.get(); + final Deque stack = castNonNull(THREAD_CONTEXT_STACK.get()); final List path = context.getObjectPath(); if (path != null) { for (Context context1 : stack) { @@ -203,11 +203,11 @@ public static void push(Context context) { } public static Context peek() { - return castNonNull(THREAD_CONTEXT_STACK.get().peek()); + return castNonNull(castNonNull(THREAD_CONTEXT_STACK.get()).peek()); } public static void pop(Context context) { - Context x = THREAD_CONTEXT_STACK.get().pop(); + Context x = castNonNull(THREAD_CONTEXT_STACK.get()).pop(); assert x == context; } @@ -333,7 +333,7 @@ public CalciteSignature(String sql, List parameterList, long maxRowCount, Bindable bindable) { this(sql, parameterList, internalParameters, rowType, columns, cursorFactory, rootSchema, collationList, maxRowCount, bindable, - null); + castNonNull(null)); } public CalciteSignature(String sql, @@ -346,7 +346,7 @@ public CalciteSignature(String sql, List collationList, long maxRowCount, @Nullable Bindable bindable, - Meta.@Nullable StatementType statementType) { + Meta.StatementType statementType) { super(columns, sql, parameterList, internalParameters, cursorFactory, statementType); this.rowType = rowType; diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java index a021fe2dc176..4ffa5bb9a652 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java @@ -692,7 +692,8 @@ public NavigableSet getFunctionNames() { } public Set getSubSchemaNames() { - return CalciteSchema.this.getSubSchemaMap().keySet(); + //noinspection RedundantCast + return (Set) CalciteSchema.this.getSubSchemaMap().keySet(); } public SchemaPlus add(String name, Schema schema) { diff --git a/core/src/main/java/org/apache/calcite/materialize/Lattice.java b/core/src/main/java/org/apache/calcite/materialize/Lattice.java index 7d97d65e24bd..aedbd4163e31 100644 --- a/core/src/main/java/org/apache/calcite/materialize/Lattice.java +++ b/core/src/main/java/org/apache/calcite/materialize/Lattice.java @@ -66,6 +66,11 @@ import com.google.common.collect.Multimap; import com.google.common.collect.Ordering; +import org.checkerframework.checker.initialization.qual.UnknownInitialization; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.RequiresNonNull; + import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -82,9 +87,11 @@ import java.util.function.IntFunction; import java.util.stream.Collectors; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Structure that allows materialized views based upon a star schema to be * recognized and recommended. @@ -128,8 +135,10 @@ private Lattice(CalciteSchema rootSchema, LatticeRootNode rootNode, } Preconditions.checkArgument(rowCountEstimate > 0d); this.rowCountEstimate = rowCountEstimate; - this.statisticProvider = + @SuppressWarnings("argument.type.incompatible") + LatticeStatisticProvider statisticProvider = Objects.requireNonNull(statisticProviderFactory.apply(this)); + this.statisticProvider = statisticProvider; } /** Creates a Lattice. */ @@ -137,7 +146,10 @@ public static Lattice create(CalciteSchema schema, String sql, boolean auto) { return builder(schema, sql).auto(auto).build(); } - private boolean isValid(Litmus litmus) { + @RequiresNonNull({"rootNode", "defaultMeasures", "columns"}) + private boolean isValid( + @UnknownInitialization Lattice this, + Litmus litmus) { if (!rootNode.isValid(litmus)) { return false; } @@ -152,7 +164,7 @@ private boolean isValid(Litmus litmus) { return litmus.succeed(); } - private static void populateAliases(SqlNode from, List aliases, + private static void populateAliases(SqlNode from, List<@Nullable String> aliases, @Nullable String current) { if (from instanceof SqlJoin) { SqlJoin join = (SqlJoin) from; @@ -375,7 +387,10 @@ public String countSql(ImmutableBitSet groupSet) { public StarTable createStarTable() { final List tables = new ArrayList<>(); for (LatticeNode node : rootNode.descendants) { - tables.add(node.table.t.unwrap(Table.class)); + tables.add( + assertNonNull( + node.table.t.unwrap(Table.class), + () -> "can't get table for " + node.table.t)); } return StarTable.of(this, tables); } @@ -524,9 +539,9 @@ Vertex getSource() { /** Vertex in the temporary graph. */ private static class Vertex { final LatticeTable table; - final String alias; + final @Nullable String alias; - private Vertex(LatticeTable table, String alias) { + private Vertex(LatticeTable table, @Nullable String alias) { this.table = table; this.alias = alias; } @@ -542,7 +557,7 @@ private Vertex(LatticeTable table, String alias) { public static class Measure implements Comparable { public final SqlAggFunction agg; public final boolean distinct; - @Nullable public final String name; + public final @Nullable String name; public final ImmutableList args; public final String digest; @@ -673,7 +688,7 @@ public int compareTo(Column column) { public abstract void toSql(SqlWriter writer); /** The alias that SQL would give to this expression. */ - public abstract String defaultAlias(); + public abstract @Nullable String defaultAlias(); } /** Column in a lattice. Columns are identified by table alias and @@ -730,7 +745,7 @@ public void toSql(SqlWriter writer) { writer.write(e); } - public String defaultAlias() { + public @Nullable String defaultAlias() { // there is no default alias for an expression return null; } @@ -779,9 +794,9 @@ public static class Builder { private boolean algorithm = false; private long algorithmMaxMillis = -1; private boolean auto = true; - private Double rowCountEstimate; - private String statisticProvider; - private Map derivedColumnsByName = + private @MonotonicNonNull Double rowCountEstimate; + private @Nullable String statisticProvider; + private final Map derivedColumnsByName = new LinkedHashMap<>(); public Builder(LatticeSpace space, CalciteSchema schema, String sql) { @@ -797,15 +812,18 @@ public Builder(LatticeSpace space, CalciteSchema schema, String sql) { populate(relNodes, tempLinks, parsed.root.rel); // Get aliases. - List aliases = new ArrayList<>(); - populateAliases(((SqlSelect) parsed.sqlNode).getFrom(), aliases, null); + List<@Nullable String> aliases = new ArrayList<>(); + SqlNode from = ((SqlSelect) parsed.sqlNode).getFrom(); + assert from != null : "from must not be null"; + populateAliases(from, aliases, null); // Build a graph. final DirectedGraph graph = DefaultDirectedGraph.create(Edge.FACTORY); final List vertices = new ArrayList<>(); - for (Pair p : Pair.zip(relNodes, aliases)) { - final LatticeTable table = space.register(p.left.getTable()); + for (Pair p : Pair.zip(relNodes, aliases)) { + final LatticeTable table = space.register( + assertNonNull(p.left.getTable(), () -> "no table for " + p.left)); final Vertex vertex = new Vertex(table, p.right); graph.addVertex(vertex); vertices.add(vertex); @@ -815,7 +833,7 @@ public Builder(LatticeSpace space, CalciteSchema schema, String sql) { final Vertex target = vertices.get(tempLink[1][0]); Edge edge = graph.getEdge(source, target); if (edge == null) { - edge = graph.addEdge(source, target); + edge = castNonNull(graph.addEdge(source, target)); } edge.pairs.add(IntPair.of(tempLink[0][1], tempLink[1][1])); } @@ -907,7 +925,7 @@ public Builder rowCountEstimate(double rowCountEstimate) { /** Sets the "statisticProvider" attribute. * *

If not set, the lattice will use {@link Lattices#CACHED_SQL}. */ - public Builder statisticProvider(String statisticProvider) { + public Builder statisticProvider(@Nullable String statisticProvider) { this.statisticProvider = statisticProvider; return this; } @@ -1108,7 +1126,7 @@ void fixUp(MutableNode node) { final String alias = SqlValidatorUtil.uniquify(name, columnAliases, SqlValidatorUtil.ATTEMPT_SUGGESTER); final BaseColumn column = - new BaseColumn(c++, node.alias, name, alias); + new BaseColumn(c++, castNonNull(node.alias), name, alias); columnList.add(column); columnAliasList.put(name, column); // name before it is made unique } 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 9bf5ac2a3369..c929eb2ab4da 100644 --- a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java +++ b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java @@ -64,7 +64,7 @@ public class MaterializationService { new MaterializationService(); /** For testing. */ - private static final ThreadLocal THREAD_INSTANCE = + private static final ThreadLocal<@Nullable MaterializationService> THREAD_INSTANCE = ThreadLocal.withInitial(MaterializationService::new); private static final Comparator> C = diff --git a/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java b/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java index 1b3c46a20047..ea716cd2125a 100644 --- a/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java +++ b/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java @@ -28,7 +28,10 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.initialization.qual.UnknownInitialization; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; import org.slf4j.Logger; import java.text.NumberFormat; @@ -66,9 +69,9 @@ public abstract class AbstractRelOptPlanner implements RelOptPlanner { protected final RelOptCostFactory costFactory; - private @Nullable MulticastRelOptListener listener; + private @MonotonicNonNull MulticastRelOptListener listener; - private @Nullable RuleAttemptsListener ruleAttemptsListener; + private @MonotonicNonNull RuleAttemptsListener ruleAttemptsListener; private @Nullable Pattern ruleDescExclusionFilter; @@ -175,11 +178,11 @@ public boolean removeRule(RelOptRule rule) { * @param description Description * @return Rule with given description, or null if not found */ - protected RelOptRule getRuleByDescription(String description) { + protected @Nullable RelOptRule getRuleByDescription(String description) { return mapDescToRule.get(description); } - public void setRuleDescExclusionFilter(Pattern exclusionFilter) { + public void setRuleDescExclusionFilter(@Nullable Pattern exclusionFilter) { ruleDescExclusionFilter = exclusionFilter; } @@ -255,7 +258,9 @@ public RelTraitSet emptyTraitSet() { return getCost(rel, mq); } - public void addListener(RelOptListener newListener) { + public void addListener( + @UnknownInitialization AbstractRelOptPlanner this, + RelOptListener newListener) { if (listener == null) { listener = new MulticastRelOptListener(); } @@ -427,6 +432,7 @@ protected void notifyDiscard(RelNode rel) { } } + @Pure public @Nullable RelOptListener getListener() { return listener; } diff --git a/core/src/main/java/org/apache/calcite/plan/Convention.java b/core/src/main/java/org/apache/calcite/plan/Convention.java index ba660a750308..76a6ecfa6845 100644 --- a/core/src/main/java/org/apache/calcite/plan/Convention.java +++ b/core/src/main/java/org/apache/calcite/plan/Convention.java @@ -124,7 +124,7 @@ public RelTraitDef getTraitDef() { return ConventionTraitDef.INSTANCE; } - @Override public RelNode enforce(final RelNode input, + @Override public @Nullable RelNode enforce(final RelNode input, final RelTraitSet required) { return null; } diff --git a/core/src/main/java/org/apache/calcite/plan/ConventionTraitDef.java b/core/src/main/java/org/apache/calcite/plan/ConventionTraitDef.java index d38d296ad0c3..ad5ff2507a0e 100644 --- a/core/src/main/java/org/apache/calcite/plan/ConventionTraitDef.java +++ b/core/src/main/java/org/apache/calcite/plan/ConventionTraitDef.java @@ -31,6 +31,8 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -122,7 +124,7 @@ public void deregisterConverterRule( } // implement RelTraitDef - public RelNode convert( + public @Nullable RelNode convert( RelOptPlanner planner, RelNode rel, Convention toConvention, diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptCluster.java b/core/src/main/java/org/apache/calcite/plan/RelOptCluster.java index b4991982094b..98bd4ddc8d64 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptCluster.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptCluster.java @@ -30,12 +30,18 @@ import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.rex.RexNode; +import org.checkerframework.checker.initialization.qual.UnknownInitialization; +import org.checkerframework.checker.nullness.qual.EnsuresNonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * An environment for related relational expressions during the * optimization of a query. @@ -44,16 +50,16 @@ public class RelOptCluster { //~ Instance fields -------------------------------------------------------- private final RelDataTypeFactory typeFactory; - private RelOptPlanner planner; + private final RelOptPlanner planner; private final AtomicInteger nextCorrel; private final Map mapCorrelToRel; private RexNode originalExpression; private final RexBuilder rexBuilder; private RelMetadataProvider metadataProvider; private MetadataFactory metadataFactory; - private HintStrategyTable hintStrategies; + private @Nullable HintStrategyTable hintStrategies; private final RelTraitSet emptyTraitSet; - private RelMetadataQuery mq; + private @Nullable RelMetadataQuery mq; private Supplier mqSupplier; //~ Constructors ----------------------------------------------------------- @@ -105,7 +111,7 @@ public static RelOptCluster create(RelOptPlanner planner, @Deprecated // to be removed before 2.0 public RelOptQuery getQuery() { - return new RelOptQuery(planner, nextCorrel, mapCorrelToRel); + return new RelOptQuery(castNonNull(planner), nextCorrel, mapCorrelToRel); } @Deprecated // to be removed before 2.0 @@ -130,7 +136,7 @@ public RexBuilder getRexBuilder() { return rexBuilder; } - public RelMetadataProvider getMetadataProvider() { + public @Nullable RelMetadataProvider getMetadataProvider() { return metadataProvider; } @@ -139,7 +145,10 @@ public RelMetadataProvider getMetadataProvider() { * * @param metadataProvider custom provider */ - public void setMetadataProvider(RelMetadataProvider metadataProvider) { + @EnsuresNonNull({"this.metadataProvider", "this.metadataFactory"}) + public void setMetadataProvider( + @UnknownInitialization RelOptCluster this, + RelMetadataProvider metadataProvider) { this.metadataProvider = metadataProvider; this.metadataFactory = new MetadataFactoryImpl(metadataProvider); // Wrap the metadata provider as a JaninoRelMetadataProvider @@ -162,7 +171,10 @@ public MetadataFactory getMetadataFactory() { * cached in this cluster, and we may invalidate and re-generate it * for each {@link RelOptRuleCall} cycle. */ - public void setMetadataQuerySupplier(Supplier mqSupplier) { + @EnsuresNonNull("this.mqSupplier") + public void setMetadataQuerySupplier( + @UnknownInitialization RelOptCluster this, + Supplier mqSupplier) { this.mqSupplier = mqSupplier; } @@ -175,7 +187,7 @@ public void setMetadataQuerySupplier(Supplier mqSupplier) { * method, then use {@link RelOptRuleCall#getMetadataQuery()} instead. */ public RelMetadataQuery getMetadataQuery() { if (mq == null) { - mq = this.mqSupplier.get(); + mq = castNonNull(mqSupplier).get(); } return mq; } diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptLattice.java b/core/src/main/java/org/apache/calcite/plan/RelOptLattice.java index 2b823e7d0576..fd5286aa8c8e 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptLattice.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptLattice.java @@ -25,6 +25,8 @@ import org.apache.calcite.util.ImmutableBitSet; import org.apache.calcite.util.Pair; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -50,7 +52,7 @@ public RelOptTable rootTable() { * @param node Relational expression * @return Rewritten query */ - public RelNode rewrite(RelNode node) { + public @Nullable RelNode rewrite(RelNode node) { return RelOptMaterialization.tryUseStar(node, starRelOptTable); } @@ -69,7 +71,7 @@ public RelNode rewrite(RelNode node) { * @param measureList Calls to aggregate functions * @return Materialized table */ - public Pair getAggregate( + public @Nullable Pair getAggregate( RelOptPlanner planner, ImmutableBitSet groupSet, List measureList) { final CalciteConnectionConfig config = @@ -80,6 +82,7 @@ public Pair getAggregate( final MaterializationService service = MaterializationService.instance(); boolean create = lattice.auto && config.createMaterializations(); final CalciteSchema schema = starRelOptTable.unwrap(CalciteSchema.class); + assert schema != null : "Can't get CalciteSchema from " + starRelOptTable; return service.defineTile(lattice, groupSet, measureList, schema, create, false); } diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptListener.java b/core/src/main/java/org/apache/calcite/plan/RelOptListener.java index 64d6203e565d..92c5e6226c7d 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptListener.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptListener.java @@ -18,6 +18,8 @@ import org.apache.calcite.rel.RelNode; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.EventListener; import java.util.EventObject; @@ -86,21 +88,21 @@ public interface RelOptListener extends EventListener { * source of an event is typically the RelOptPlanner which initiated it. */ abstract class RelEvent extends EventObject { - private final RelNode rel; + private final @Nullable RelNode rel; - protected RelEvent(Object eventSource, RelNode rel) { + protected RelEvent(Object eventSource, @Nullable RelNode rel) { super(eventSource); this.rel = rel; } - public RelNode getRel() { + public @Nullable RelNode getRel() { return rel; } } /** Event indicating that a relational expression has been chosen. */ class RelChosenEvent extends RelEvent { - public RelChosenEvent(Object eventSource, RelNode rel) { + public RelChosenEvent(Object eventSource, @Nullable RelNode rel) { super(eventSource, rel); } } diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java b/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java index 02027c9c8918..03700debf8af 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptMaterialization.java @@ -44,6 +44,8 @@ import java.util.List; import java.util.Objects; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Records that a particular query is materialized by a particular table. */ @@ -60,7 +62,10 @@ public class RelOptMaterialization { public RelOptMaterialization(RelNode tableRel, RelNode queryRel, @Nullable RelOptTable starRelOptTable, List qualifiedTableName) { this.tableRel = - RelOptUtil.createCastRel(tableRel, queryRel.getRowType(), false); + RelOptUtil.createCastRel( + Objects.requireNonNull(tableRel, "tableRel"), + Objects.requireNonNull(queryRel, "queryRel").getRowType(), + false); this.starRelOptTable = starRelOptTable; if (starRelOptTable == null) { this.starTable = null; @@ -91,7 +96,7 @@ public RelOptMaterialization(RelNode tableRel, RelNode queryRel, @Override public RelNode visit(TableScan scan) { RelOptTable relOptTable = scan.getTable(); final Table table = relOptTable.unwrap(Table.class); - if (table.equals(starTable.tables.get(0))) { + if (Objects.equals(table, starTable.tables.get(0))) { Mappings.TargetMapping mapping = Mappings.createShiftMapping( starRelOptTable.getRowType().getFieldCount(), @@ -101,7 +106,7 @@ public RelOptMaterialization(RelNode tableRel, RelNode queryRel, final RelNode scan2 = starRelOptTable.toRel(ViewExpanders.simpleContext(cluster)); return RelOptUtil.createProject(scan2, - Mappings.asList(mapping.inverse())); + Mappings.asListNonNull(mapping.inverse())); } return scan; } @@ -142,6 +147,7 @@ private void match(ProjectFilterTable left, ProjectFilterTable right, final RelOptTable rightRelOptTable = right.getTable(); final Table rightTable = rightRelOptTable.unwrap(Table.class); if (leftTable instanceof StarTable + && rightTable != null && ((StarTable) leftTable).tables.contains(rightTable)) { final int offset = ((StarTable) leftTable).columnOffset(rightTable); @@ -152,7 +158,7 @@ private void match(ProjectFilterTable left, ProjectFilterTable right, leftMapping.getTargetCount())); final RelNode project = RelOptUtil.createProject( leftRelOptTable.toRel(ViewExpanders.simpleContext(cluster)), - Mappings.asList(mapping.inverse())); + Mappings.asListNonNull(mapping.inverse())); final List conditions = new ArrayList<>(); if (left.condition != null) { conditions.add(left.condition); @@ -167,6 +173,7 @@ private void match(ProjectFilterTable left, ProjectFilterTable right, throw new Util.FoundOne(filter); } if (rightTable instanceof StarTable + && leftTable != null && ((StarTable) rightTable).tables.contains(leftTable)) { final int offset = ((StarTable) rightTable).columnOffset(leftTable); @@ -176,7 +183,7 @@ private void match(ProjectFilterTable left, ProjectFilterTable right, Mappings.offsetTarget(rightMapping, leftCount)); final RelNode project = RelOptUtil.createProject( rightRelOptTable.toRel(ViewExpanders.simpleContext(cluster)), - Mappings.asList(mapping.inverse())); + Mappings.asListNonNull(mapping.inverse())); final List conditions = new ArrayList<>(); if (left.condition != null) { conditions.add( @@ -202,25 +209,25 @@ private void match(ProjectFilterTable left, ProjectFilterTable right, CoreRules.AGGREGATE_FILTER_TRANSPOSE), false, DefaultRelMetadataProvider.INSTANCE); - return program.run(null, rel2, null, + return program.run(castNonNull(null), rel2, castNonNull(null), ImmutableList.of(), ImmutableList.of()); } /** A table scan and optional project mapping and filter condition. */ private static class ProjectFilterTable { - final RexNode condition; - final Mappings.TargetMapping mapping; + final @Nullable RexNode condition; + final Mappings.@Nullable TargetMapping mapping; final TableScan scan; - private ProjectFilterTable(RexNode condition, - Mappings.TargetMapping mapping, TableScan scan) { + private ProjectFilterTable(@Nullable RexNode condition, + Mappings.@Nullable TargetMapping mapping, TableScan scan) { this.condition = condition; this.mapping = mapping; this.scan = Objects.requireNonNull(scan); } - static ProjectFilterTable of(RelNode node) { + static @Nullable ProjectFilterTable of(RelNode node) { if (node instanceof Filter) { final Filter filter = (Filter) node; return of2(filter.getCondition(), filter.getInput()); @@ -229,7 +236,7 @@ static ProjectFilterTable of(RelNode node) { } } - private static ProjectFilterTable of2(RexNode condition, RelNode node) { + private static @Nullable ProjectFilterTable of2(@Nullable RexNode condition, RelNode node) { if (node instanceof Project) { final Project project = (Project) node; return of3(condition, project.getMapping(), project.getInput()); @@ -238,8 +245,8 @@ private static ProjectFilterTable of2(RexNode condition, RelNode node) { } } - private static ProjectFilterTable of3(RexNode condition, - Mappings.TargetMapping mapping, RelNode node) { + private static @Nullable ProjectFilterTable of3(@Nullable RexNode condition, + Mappings.@Nullable TargetMapping mapping, RelNode node) { if (node instanceof TableScan) { return new ProjectFilterTable(condition, mapping, (TableScan) node); @@ -278,7 +285,7 @@ public static RelNode toLeafJoinForm(RelNode rel) { RelOptUtil.dumpPlan("before", rel, SqlExplainFormat.TEXT, SqlExplainLevel.DIGEST_ATTRIBUTES)); } - final RelNode rel2 = program.run(null, rel, null, + final RelNode rel2 = program.run(castNonNull(null), rel, castNonNull(null), ImmutableList.of(), ImmutableList.of()); if (CalciteSystemProperty.DEBUG.value()) { diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java b/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java index 7ab2e0ed6112..b3ec59e067c5 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptPlanner.java @@ -54,7 +54,7 @@ public interface RelOptPlanner { * * @return Root node */ - RelNode getRoot(); + @Nullable RelNode getRoot(); /** * Registers a rel trait definition. If the {@link RelTraitDef} has already @@ -125,7 +125,7 @@ public interface RelOptPlanner { * @param exclusionFilter pattern to match for exclusion; null to disable * filtering */ - void setRuleDescExclusionFilter(Pattern exclusionFilter); + void setRuleDescExclusionFilter(@Nullable Pattern exclusionFilter); /** * Does nothing. @@ -235,7 +235,7 @@ public interface RelOptPlanner { */ RelNode register( RelNode rel, - RelNode equivRel); + @Nullable RelNode equivRel); /** * Registers a relational expression if it is not already registered. diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptQuery.java b/core/src/main/java/org/apache/calcite/plan/RelOptQuery.java index d0951615b5d2..03efd0175f6d 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptQuery.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptQuery.java @@ -21,6 +21,8 @@ import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.rex.RexBuilder; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -114,7 +116,7 @@ public String createCorrel() { /** * Returns the relational expression which populates a correlating variable. */ - public RelNode lookupCorrel(String name) { + public @Nullable RelNode lookupCorrel(String name) { return mapCorrelToRel.get(name); } diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptRule.java b/core/src/main/java/org/apache/calcite/plan/RelOptRule.java index d2ad4d8c7a55..c9b7a58dabfa 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptRule.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptRule.java @@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import org.checkerframework.checker.initialization.qual.UnderInitialization; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.ArrayList; @@ -97,7 +98,7 @@ public RelOptRule(RelOptRuleOperand operand, String description) { * @param relBuilderFactory Builder for relational expressions */ public RelOptRule(RelOptRuleOperand operand, - RelBuilderFactory relBuilderFactory, String description) { + RelBuilderFactory relBuilderFactory, @Nullable String description) { this.operand = Objects.requireNonNull(operand); this.relBuilderFactory = Objects.requireNonNull(relBuilderFactory); if (description == null) { @@ -109,7 +110,7 @@ public RelOptRule(RelOptRuleOperand operand, } this.description = description; this.operands = flattenOperands(operand); - assignSolveOrder(); + assignSolveOrder(operands); } //~ Methods for creating operands ------------------------------------------ @@ -376,6 +377,7 @@ public static RelOptRuleOperandChildren any() { * @return Flattened list of operands */ private List flattenOperands( + @UnderInitialization RelOptRule this, RelOptRuleOperand rootOperand) { final List operandList = new ArrayList<>(); @@ -396,6 +398,7 @@ private List flattenOperands( * @param parentOperand Parent of this operand */ private void flattenRecurse( + @UnderInitialization RelOptRule this, List operandList, RelOptRuleOperand parentOperand) { int k = 0; @@ -413,7 +416,7 @@ private void flattenRecurse( * Builds each operand's solve-order. Start with itself, then its parent, up * to the root, then the remaining operands in prefix order. */ - private void assignSolveOrder() { + private static void assignSolveOrder(List operands) { for (RelOptRuleOperand operand : operands) { operand.solveOrder = new int[operands.size()]; int m = 0; diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptRuleOperand.java b/core/src/main/java/org/apache/calcite/plan/RelOptRuleOperand.java index 53811dfc2f05..ace9d40dcf12 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptRuleOperand.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptRuleOperand.java @@ -20,6 +20,9 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.initialization.qual.NotOnlyInitialized; +import org.checkerframework.checker.initialization.qual.UnknownInitialization; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.List; @@ -41,12 +44,12 @@ public class RelOptRuleOperand { //~ Instance fields -------------------------------------------------------- private @Nullable RelOptRuleOperand parent; - private RelOptRule rule; + private @NotOnlyInitialized RelOptRule rule; private final Predicate predicate; // REVIEW jvs 29-Aug-2004: some of these are Volcano-specific and should be // factored out - public int[] solveOrder; + public int @MonotonicNonNull [] solveOrder; public int ordinalInParent; public int ordinalInRule; public final @Nullable RelTrait trait; @@ -166,7 +169,8 @@ public RelOptRule getRule() { * * @param rule containing rule */ - public void setRule(RelOptRule rule) { + @SuppressWarnings("initialization.invalid.field.write.initialized") + public void setRule(@UnknownInitialization RelOptRule rule) { this.rule = rule; } diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptSchemaWithSampling.java b/core/src/main/java/org/apache/calcite/plan/RelOptSchemaWithSampling.java index f080f977cffd..a4cc4e29b3b2 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptSchemaWithSampling.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptSchemaWithSampling.java @@ -16,6 +16,8 @@ */ package org.apache.calcite.plan; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -37,8 +39,8 @@ public interface RelOptSchemaWithSampling extends RelOptSchema { * dataset is found; may be null * @return Table, or null if not found */ - RelOptTable getTableForMember( + @Nullable RelOptTable getTableForMember( List names, - String datasetName, - boolean[] usedDataset); + @Nullable String datasetName, + boolean @Nullable [] usedDataset); } diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java index cf7e6d587157..e5325e465a28 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java @@ -3086,12 +3086,12 @@ public static RelNode replaceInput( public static RelNode createProject( RelNode child, Mappings.TargetMapping mapping) { - return createProject(child, Mappings.asList(mapping.inverse())); + return createProject(child, Mappings.asListNonNull(mapping.inverse())); } public static RelNode createProject(RelNode child, Mappings.TargetMapping mapping, RelFactories.ProjectFactory projectFactory) { - return createProject(projectFactory, child, Mappings.asList(mapping.inverse())); + return createProject(projectFactory, child, Mappings.asListNonNull(mapping.inverse())); } /** Returns whether relational expression {@code target} occurs within a diff --git a/core/src/main/java/org/apache/calcite/plan/RelRule.java b/core/src/main/java/org/apache/calcite/plan/RelRule.java index edf62de515b4..bd052abfe643 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelRule.java +++ b/core/src/main/java/org/apache/calcite/plan/RelRule.java @@ -23,6 +23,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -245,7 +247,7 @@ private static class OperandDetailBuilderImpl private final OperandBuilderImpl parent; private final Class relClass; final OperandBuilderImpl inputBuilder = new OperandBuilderImpl(); - private RelTrait trait; + private @Nullable RelTrait trait; private Predicate predicate = r -> true; OperandDetailBuilderImpl(OperandBuilderImpl parent, Class relClass) { diff --git a/core/src/main/java/org/apache/calcite/plan/RelTraitDef.java b/core/src/main/java/org/apache/calcite/plan/RelTraitDef.java index c9d99e178144..40bc15d6e565 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelTraitDef.java +++ b/core/src/main/java/org/apache/calcite/plan/RelTraitDef.java @@ -22,6 +22,8 @@ import com.google.common.collect.Interner; import com.google.common.collect.Interners; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * RelTraitDef represents a class of {@link RelTrait}s. Implementations of * RelTraitDef may be singletons under the following conditions: @@ -115,7 +117,7 @@ assert getTraitClass().isInstance(trait) * converters are allowed * @return a converted RelNode or null if conversion is not possible */ - public abstract RelNode convert( + public abstract @Nullable RelNode convert( RelOptPlanner planner, RelNode rel, T toTrait, diff --git a/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java b/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java index 8233f9955fd5..7016fca1c0d4 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java +++ b/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java @@ -379,9 +379,9 @@ public RelTraitSet getDefaultSansConvention() { * {@link RelDistributionTraitDef#INSTANCE} is not registered * in this traitSet. */ + @SuppressWarnings("unchecked") public @Nullable T getDistribution() { - //noinspection unchecked - return (T) getTrait(RelDistributionTraitDef.INSTANCE); + return (@Nullable T) getTrait(RelDistributionTraitDef.INSTANCE); } /** @@ -390,9 +390,9 @@ public RelTraitSet getDefaultSansConvention() { * {@link RelCollationTraitDef#INSTANCE} is not registered * in this traitSet. */ + @SuppressWarnings("unchecked") public @Nullable T getCollation() { - //noinspection unchecked - return (T) getTrait(RelCollationTraitDef.INSTANCE); + return (@Nullable T) getTrait(RelCollationTraitDef.INSTANCE); } /** diff --git a/core/src/main/java/org/apache/calcite/plan/hep/HepInstruction.java b/core/src/main/java/org/apache/calcite/plan/hep/HepInstruction.java index 329f0fe27e67..93a6e21fe5a2 100644 --- a/core/src/main/java/org/apache/calcite/plan/hep/HepInstruction.java +++ b/core/src/main/java/org/apache/calcite/plan/hep/HepInstruction.java @@ -18,6 +18,8 @@ import org.apache.calcite.plan.RelOptRule; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -42,13 +44,13 @@ void initialize(boolean clearCache) { * * @param rule type */ static class RuleClass extends HepInstruction { - Class ruleClass; + @Nullable Class ruleClass; /** * Actual rule set instantiated during planning by filtering all of the * planner's rules through ruleClass. */ - Set ruleSet; + @Nullable Set ruleSet; void initialize(boolean clearCache) { if (!clearCache) { @@ -68,7 +70,7 @@ static class RuleCollection extends HepInstruction { /** * Collection of rules to apply. */ - Collection rules; + @Nullable Collection rules; void execute(HepPlanner planner) { planner.executeInstruction(this); @@ -83,7 +85,7 @@ static class ConverterRules extends HepInstruction { * Actual rule set instantiated during planning by filtering all of the * planner's rules, looking for the desired converters. */ - Set ruleSet; + @Nullable Set ruleSet; void execute(HepPlanner planner) { planner.executeInstruction(this); @@ -92,7 +94,7 @@ void execute(HepPlanner planner) { /** Instruction that finds common relational sub-expressions. */ static class CommonRelSubExprRules extends HepInstruction { - Set ruleSet; + @Nullable Set ruleSet; void execute(HepPlanner planner) { planner.executeInstruction(this); @@ -104,13 +106,13 @@ static class RuleInstance extends HepInstruction { /** * Description to look for, or null if rule specified explicitly. */ - String ruleDescription; + @Nullable String ruleDescription; /** * Explicitly specified rule, or rule looked up by planner from * description. */ - RelOptRule rule; + @Nullable RelOptRule rule; void initialize(boolean clearCache) { if (!clearCache) { @@ -130,7 +132,7 @@ void execute(HepPlanner planner) { /** Instruction that sets match order. */ static class MatchOrder extends HepInstruction { - HepMatchOrder order; + @Nullable HepMatchOrder order; void execute(HepPlanner planner) { planner.executeInstruction(this); @@ -148,10 +150,12 @@ void execute(HepPlanner planner) { /** Instruction that executes a sub-program. */ static class Subprogram extends HepInstruction { - HepProgram subprogram; + @Nullable HepProgram subprogram; void initialize(boolean clearCache) { - subprogram.initialize(clearCache); + if (subprogram != null) { + subprogram.initialize(clearCache); + } } void execute(HepPlanner planner) { @@ -161,7 +165,7 @@ void execute(HepPlanner planner) { /** Instruction that begins a group. */ static class BeginGroup extends HepInstruction { - EndGroup endGroup; + @Nullable EndGroup endGroup; void initialize(boolean clearCache) { } @@ -177,7 +181,7 @@ static class EndGroup extends HepInstruction { * Actual rule set instantiated during planning by collecting grouped * rules. */ - Set ruleSet; + @Nullable Set ruleSet; boolean collecting; diff --git a/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java b/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java index a1a305b81d48..4794c1dab1b1 100644 --- a/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java +++ b/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java @@ -162,7 +162,7 @@ public void setRoot(RelNode rel) { } // implement RelOptPlanner - public RelNode getRoot() { + public @Nullable RelNode getRoot() { return root; } @@ -220,12 +220,14 @@ private void executeProgram(HepProgram program) { void executeInstruction( HepInstruction.MatchLimit instruction) { LOGGER.trace("Setting match limit to {}", instruction.limit); + assert currentProgram != null : "currentProgram must not be null"; currentProgram.matchLimit = instruction.limit; } void executeInstruction( HepInstruction.MatchOrder instruction) { LOGGER.trace("Setting match order to {}", instruction.order); + assert currentProgram != null : "currentProgram must not be null"; currentProgram.matchOrder = instruction.order; } @@ -254,6 +256,7 @@ void executeInstruction( return; } LOGGER.trace("Applying rule class {}", instruction.ruleClass); + assert instruction.ruleClass != null : "instruction.ruleClass must not be null"; if (instruction.ruleSet == null) { instruction.ruleSet = new LinkedHashSet<>(); for (RelOptRule rule : mapDescToRule.values()) { @@ -270,11 +273,12 @@ void executeInstruction( if (skippingGroup()) { return; } + assert instruction.rules != null : "instruction.rules must not be null"; applyRules(instruction.rules, true); } private boolean skippingGroup() { - if (currentProgram.group != null) { + if (currentProgram != null && currentProgram.group != null) { // Skip if we've already collected the ruleset. return !currentProgram.group.collecting; } else { @@ -285,6 +289,7 @@ private boolean skippingGroup() { void executeInstruction( HepInstruction.ConverterRules instruction) { + assert currentProgram != null : "currentProgram must not be null"; assert currentProgram.group == null; if (instruction.ruleSet == null) { instruction.ruleSet = new LinkedHashSet<>(); @@ -311,6 +316,7 @@ void executeInstruction( } void executeInstruction(HepInstruction.CommonRelSubExprRules instruction) { + assert currentProgram != null : "currentProgram must not be null"; assert currentProgram.group == null; if (instruction.ruleSet == null) { instruction.ruleSet = new LinkedHashSet<>(); @@ -347,6 +353,7 @@ void executeInstruction( void executeInstruction( HepInstruction.EndGroup instruction) { + assert currentProgram != null : "currentProgram must not be null"; assert currentProgram.group == instruction; currentProgram.group = null; instruction.collecting = false; @@ -365,6 +372,7 @@ private int depthFirstApply(Iterator iter, if (newVertex == null || newVertex == vertex) { continue; } + assert currentProgram != null : "currentProgram must not be null"; ++nMatches; if (nMatches >= currentProgram.matchLimit) { return nMatches; @@ -384,6 +392,7 @@ private int depthFirstApply(Iterator iter, private void applyRules( Collection rules, boolean forceConversions) { + assert currentProgram != null : "currentProgram must not be null"; if (currentProgram.group != null) { assert currentProgram.group.collecting; currentProgram.group.ruleSet.addAll(rules); @@ -449,6 +458,7 @@ private Iterator getGraphIterator(HepRelVertex start) { // better optimizer performance. collectGarbage(); + assert currentProgram != null : "currentProgram must not be null"; switch (currentProgram.matchOrder) { case ARBITRARY: case DEPTH_FIRST: @@ -693,7 +703,10 @@ private HepRelVertex applyTransformationResults( LOGGER.trace("considering {} with cumulative cost={} and rowcount={}", rel, thisCost, mq.getRowCount(rel)); } - if ((bestRel == null) || thisCost.isLt(bestCost)) { + if (thisCost == null) { + continue; + } + if (bestRel == null || thisCost.isLt(bestCost)) { bestRel = rel; bestCost = thisCost; } @@ -765,7 +778,7 @@ private HepRelVertex applyTransformationResults( // implement RelOptPlanner public RelNode register( RelNode rel, - RelNode equivRel) { + @Nullable RelNode equivRel) { // Ignore; this call is mostly to tell Volcano how to avoid // infinite loops. return rel; diff --git a/core/src/main/java/org/apache/calcite/plan/hep/HepProgram.java b/core/src/main/java/org/apache/calcite/plan/hep/HepProgram.java index 83e5c88d685d..893b2403061c 100644 --- a/core/src/main/java/org/apache/calcite/plan/hep/HepProgram.java +++ b/core/src/main/java/org/apache/calcite/plan/hep/HepProgram.java @@ -18,6 +18,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -43,9 +45,9 @@ public class HepProgram { int matchLimit; - HepMatchOrder matchOrder; + @Nullable HepMatchOrder matchOrder; - HepInstruction.EndGroup group; + HepInstruction.@Nullable EndGroup group; //~ Constructors ----------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java b/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java index add516a3f10a..cd4ff1424475 100644 --- a/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java +++ b/core/src/main/java/org/apache/calcite/plan/hep/HepRelVertex.java @@ -25,6 +25,8 @@ import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.rel.type.RelDataType; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -91,7 +93,7 @@ public RelNode getCurrentRel() { return currentRel; } - @Override public boolean deepEquals(Object obj) { + @Override public boolean deepEquals(@Nullable Object obj) { return this == obj || (obj instanceof HepRelVertex && currentRel == ((HepRelVertex) obj).currentRel); diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java b/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java index 40a50ac65bc0..259c1f51b5eb 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/AbstractConverter.java @@ -30,6 +30,8 @@ import org.apache.calcite.rel.metadata.RelMetadataQuery; import org.apache.calcite.tools.RelBuilderFactory; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -51,7 +53,7 @@ public class AbstractConverter extends ConverterImpl { public AbstractConverter( RelOptCluster cluster, RelSubset rel, - RelTraitDef traitDef, + @Nullable RelTraitDef traitDef, RelTraitSet traits) { super(cluster, traitDef, traits, rel); assert traits.allSimple(); diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/Dumpers.java b/core/src/main/java/org/apache/calcite/plan/volcano/Dumpers.java index 26da2230e3a0..c4dc0262b881 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/Dumpers.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/Dumpers.java @@ -140,6 +140,10 @@ static void dumpSets(VolcanoPlanner planner, PrintWriter pw) { planner.getSubset( input, input.getTraitSet()); + if (inputSubset == null) { + pw.append("no subset found for input ").print(input.getId()); + continue; + } RelSet inputSet = inputSubset.set; if (input instanceof RelSubset) { final Iterator rels = @@ -191,7 +195,12 @@ static void dumpGraphviz(VolcanoPlanner planner, PrintWriter pw) { // Note: rel traitset could be different from its subset.traitset // It can happen due to RelTraitset#simplify // If the traits are different, we want to keep them on a graph - String traits = "." + planner.getSubset(rel).getTraitSet().toString(); + RelSubset relSubset = planner.getSubset(rel); + if (relSubset == null) { + pw.append("no subset found for rel"); + continue; + } + String traits = "." + relSubset.getTraitSet().toString(); String title = rel.toString().replace(traits, ""); if (title.endsWith(")")) { int openParen = title.indexOf('('); @@ -208,7 +217,6 @@ static void dumpGraphviz(VolcanoPlanner planner, PrintWriter pw) { title + "\nrows=" + mq.getRowCount(rel) + ", cost=" + planner.getCost(rel, mq), false); - RelSubset relSubset = planner.getSubset(rel); if (!(rel instanceof AbstractConverter)) { nonEmptySubsets.add(relSubset); } @@ -268,6 +276,10 @@ static void dumpGraphviz(VolcanoPlanner planner, PrintWriter pw) { for (RelSet set : ordering.immutableSortedCopy(planner.allSets)) { for (RelNode rel : set.rels) { RelSubset relSubset = planner.getSubset(rel); + if (relSubset == null) { + pw.append("no subset found for rel ").print(rel.getId()); + continue; + } pw.print("\tsubset"); pw.print(relSubset.getId()); pw.print(" -> rel"); diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/IterativeRuleQueue.java b/core/src/main/java/org/apache/calcite/plan/volcano/IterativeRuleQueue.java index 62394cca3e1c..27791d562a25 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/IterativeRuleQueue.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/IterativeRuleQueue.java @@ -16,12 +16,14 @@ */ package org.apache.calcite.plan.volcano; +import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.rules.SubstitutionRule; import org.apache.calcite.util.trace.CalciteTrace; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import java.io.PrintWriter; @@ -98,7 +100,7 @@ public void addMatch(VolcanoRuleMatch match) { * obsolete set or has been pruned. * */ - public VolcanoRuleMatch popMatch() { + public @Nullable VolcanoRuleMatch popMatch() { dumpPlannerState(); VolcanoRuleMatch match; @@ -110,6 +112,9 @@ public VolcanoRuleMatch popMatch() { dumpRuleQueue(matchList); match = matchList.poll(); + if (match == null) { + return null; + } if (skipMatch(match)) { LOGGER.debug("Skip match: {}", match); @@ -158,7 +163,10 @@ private void dumpPlannerState() { planner.dump(pw); pw.flush(); LOGGER.trace(sw.toString()); - planner.getRoot().getCluster().invalidateMetadataQuery(); + RelNode root = planner.getRoot(); + if (root != null) { + root.getCluster().invalidateMetadataQuery(); + } } } @@ -197,7 +205,7 @@ int size() { return preQueue.size() + queue.size(); } - VolcanoRuleMatch poll() { + @Nullable VolcanoRuleMatch poll() { VolcanoRuleMatch match = preQueue.poll(); if (match == null) { match = queue.poll(); diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java index 09cf0e97a78a..e7967c37f0ac 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java @@ -33,6 +33,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import java.util.ArrayList; @@ -43,6 +45,9 @@ import java.util.Set; import java.util.stream.Collectors; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * A RelSet is an equivalence-set of expressions; that is, a set of * expressions which have identical semantics. We are generally interested in @@ -71,13 +76,13 @@ class RelSet { * Set to the superseding set when this is found to be equivalent to another * set. */ - RelSet equivalentSet; - RelNode rel; + @MonotonicNonNull RelSet equivalentSet; + @MonotonicNonNull RelNode rel; /** * Exploring state of current RelSet. */ - ExploringState exploringState; + @Nullable ExploringState exploringState; /** * Records conversions / enforcements that have happened on the @@ -150,7 +155,7 @@ public List getRelsFromAllSubsets() { return rels; } - public RelSubset getSubset(RelTraitSet traits) { + public @Nullable RelSubset getSubset(RelTraitSet traits) { for (RelSubset subset : subsets) { if (subset.getTraitSet().equals(traits)) { return subset; @@ -206,6 +211,7 @@ void addConverters(RelSubset subset, boolean required, if (from == to || to.isEnforceDisabled() || useAbstractConverter + && from.getConvention() != null && !from.getConvention().useAbstractConvertersForConversion( from.getTraitSet(), to.getTraitSet())) { continue; @@ -241,7 +247,10 @@ void addConverters(RelSubset subset, boolean required, enforcer = new AbstractConverter( cluster, from, null, to.getTraitSet()); } else { - enforcer = subset.getConvention().enforce(from, to.getTraitSet()); + Convention convention = assertNonNull( + subset.getConvention(), + () -> "convention is null for " + subset); + enforcer = convention.enforce(from, to.getTraitSet()); } if (enforcer != null) { @@ -290,13 +299,17 @@ RelSubset getOrCreateSubset( } private void postEquivalenceEvent(VolcanoPlanner planner, RelNode rel) { + RelOptListener listener = planner.getListener(); + if (listener == null) { + return; + } RelOptListener.RelEquivalenceEvent event = new RelOptListener.RelEquivalenceEvent( planner, rel, "equivalence class " + id, false); - planner.getListener().relEquivalenceFound(event); + listener.relEquivalenceFound(event); } /** @@ -352,7 +365,7 @@ void mergeWith( assert otherSet.equivalentSet == null; LOGGER.trace("Merge set#{} into set#{}", otherSet.id, id); otherSet.equivalentSet = this; - RelOptCluster cluster = rel.getCluster(); + RelOptCluster cluster = castNonNull(rel).getCluster(); RelMetadataQuery mq = cluster.getMetadataQuery(); // remove from table @@ -385,7 +398,7 @@ void mergeWith( } // collect RelSubset instances, whose best should be changed - if (otherSubset.bestCost.isLt(subset.bestCost)) { + if (otherSubset.bestCost.isLt(subset.bestCost) && otherSubset.best != null) { changedSubsets.put(subset, otherSubset.best); } } @@ -441,7 +454,7 @@ void mergeWith( // Make sure the cost changes as a result of merging are propagated. for (RelNode parentRel : getParentRels()) { - final RelSubset parentSubset = planner.getSubset(parentRel); + final RelSubset parentSubset = planner.getSubsetNonNull(parentRel); parentSubset.propagateCostImprovements( planner, mq, parentRel, activeSet); diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java b/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java index 7fa9f7f203c8..b1518112c911 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java @@ -41,6 +41,8 @@ import com.google.common.collect.Sets; import org.apiguardian.api.API; +import org.checkerframework.checker.initialization.qual.UnderInitialization; +import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; @@ -60,6 +62,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Subset of an equivalence class where all relational expressions have the * same physical properties. @@ -89,7 +94,7 @@ public class RelSubset extends AbstractRelNode { @Nullable OptimizeState taskState; /** Cost of best known plan (it may have improved since). */ - @Nullable RelOptCost bestCost; + RelOptCost bestCost; /** The set this subset belongs to. */ final RelSet set; @@ -128,7 +133,7 @@ public class RelSubset extends AbstractRelNode { /** * The upper bound of the last OptimizeGroup call. */ - @Nullable RelOptCost upperBound; + RelOptCost upperBound; /** * A cache that recognize which RelNode has invoked the passThrough method @@ -145,7 +150,7 @@ public class RelSubset extends AbstractRelNode { super(cluster, traits); this.set = set; assert traits.allSimple(); - computeBestCost(cluster.getPlanner()); + computeBestCost(cluster, cluster.getPlanner()); upperBound = bestCost; } @@ -164,11 +169,21 @@ public class RelSubset extends AbstractRelNode { * {@link RelSet#mergeWith(VolcanoPlanner, RelSet)}. * */ - private void computeBestCost(RelOptPlanner planner) { + @EnsuresNonNull("bestCost") + private void computeBestCost( + @UnderInitialization RelSubset this, + RelOptCluster cluster, + RelOptPlanner planner + ) { bestCost = planner.getCostFactory().makeInfiniteCost(); - final RelMetadataQuery mq = getCluster().getMetadataQuery(); - for (RelNode rel : getRels()) { + final RelMetadataQuery mq = cluster.getMetadataQuery(); + @SuppressWarnings("method.invocation.invalid") + Iterable rels = getRels(); + for (RelNode rel : rels) { final RelOptCost cost = planner.getCost(rel, mq); + if (cost == null) { + continue; + } if (cost.isLt(bestCost)) { bestCost = cost; best = rel; @@ -209,7 +224,7 @@ boolean isEnforceDisabled() { return best; } - public RelNode getOriginal() { + public @Nullable RelNode getOriginal() { return set.rel; } @@ -241,7 +256,7 @@ public double estimateRowCount(RelMetadataQuery mq) { // values to be printed later. We actually do the work. pw.item("subset", toString()); final AbstractRelNode input = - (AbstractRelNode) Util.first(getBest(), getOriginal()); + (@Nullable AbstractRelNode) Util.first(getBest(), getOriginal()); if (input == null) { return; } @@ -249,7 +264,7 @@ public double estimateRowCount(RelMetadataQuery mq) { pw.done(input); } - @Override public boolean deepEquals(Object obj) { + @Override public boolean deepEquals(@Nullable Object obj) { return this == obj; } @@ -258,7 +273,7 @@ public double estimateRowCount(RelMetadataQuery mq) { } @Override protected RelDataType deriveRowType() { - return set.rel.getRowType(); + return castNonNull(set.rel).getRowType(); } /** @@ -287,7 +302,7 @@ Set getParentSubsets(VolcanoPlanner planner) { for (RelNode parent : set.getParentRels()) { for (RelSubset rel : inputSubsets(parent)) { if (rel.set == set && rel.getTraitSet().equals(traitSet)) { - list.add(planner.getSubset(parent)); + list.add(planner.getSubsetNonNull(parent)); } } } @@ -394,8 +409,8 @@ void propagateCostImprovements(VolcanoPlanner planner, RelMetadataQuery mq, } } - while (!propagationQueue.isEmpty()) { - Pair p = propagationQueue.poll(); + Pair p; + while ((p = propagationQueue.poll()) != null) { p.left.propagateCostImprovements0(planner, mq, p.right, activeSet, propagationQueue); } } @@ -417,7 +432,7 @@ void propagateCostImprovements0(VolcanoPlanner planner, RelMetadataQuery mq, // Update subset best cost when we find a cheaper rel or the current // best's cost is changed - if (cost.isLt(bestCost)) { + if (cost != null && cost.isLt(bestCost)) { LOGGER.trace("Subset cost changed: subset [{}] cost was {} now {}", this, bestCost, cost); @@ -431,7 +446,8 @@ void propagateCostImprovements0(VolcanoPlanner planner, RelMetadataQuery mq, for (RelNode parent : getParents()) { // removes parent cached metadata since its input was changed mq.clearCache(parent); - final RelSubset parentSubset = planner.getSubset(parent); + final RelSubset parentSubset = + assertNonNull(planner.getSubset(parent), "subset not found for " + parent); // parent subset will clear its cache in propagateCostImprovements0 method itself for (RelSubset subset : parentSubset.set.subsets) { @@ -661,7 +677,7 @@ private static String traitDiff(RelTraitSet original, RelTraitSet desired) { public RelNode visit( RelNode p, int ordinal, - RelNode parent) { + @Nullable RelNode parent) { if (p instanceof RelSubset) { RelSubset subset = (RelSubset) p; RelNode cheapest = subset.best; @@ -690,8 +706,11 @@ public RelNode visit( Map problemCounts = finder.deadEnds.stream() .filter(deadSubset -> deadSubset.getOriginal() != null) - .map(x -> x.getOriginal().getClass().getSimpleName() - + traitDiff(x.getOriginal().getTraitSet(), x.getTraitSet())) + .map(x -> { + RelNode original = castNonNull(x.getOriginal()); + return original.getClass().getSimpleName() + + traitDiff(original.getTraitSet(), x.getTraitSet()); + }) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); // Sort problems from most often to less often ones String problems = problemCounts.entrySet().stream() @@ -720,8 +739,10 @@ public RelNode visit( pw.print(deadEnd); pw.println(", the relevant part of the original plan is as follows"); RelNode original = deadEnd.getOriginal(); - original.explain( - new RelWriterImpl(pw, SqlExplainLevel.EXPPLAN_ATTRIBUTES, true)); + if (original != null) { + original.explain( + new RelWriterImpl(pw, SqlExplainLevel.EXPPLAN_ATTRIBUTES, true)); + } i++; rest--; if (rest > 0) { diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/TopDownRuleDriver.java b/core/src/main/java/org/apache/calcite/plan/volcano/TopDownRuleDriver.java index 0115a05adf04..c1c832a3650b 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/TopDownRuleDriver.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/TopDownRuleDriver.java @@ -25,6 +25,7 @@ import org.apache.calcite.util.Pair; import org.apache.calcite.util.trace.CalciteTrace; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import java.util.ArrayList; @@ -35,6 +36,8 @@ import java.util.Stack; import java.util.function.Predicate; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; + /** * A rule driver that apply rules in a Top-Down manner. * By ensuring rule applying orders, there could be ways for @@ -58,20 +61,20 @@ class TopDownRuleDriver implements RuleDriver { /** * All tasks waiting for execution. */ - private Stack tasks = new Stack<>(); + private final Stack tasks = new Stack<>(); /** * A task that is currently applying and may generate new RelNode. * It provides a callback to schedule tasks for new RelNodes that * are registered during task performing. */ - private GeneratorTask applying = null; + private @Nullable GeneratorTask applying = null; /** * RelNodes that are generated by passThrough or derive * these nodes will not takes part in another passThrough or derive. */ - private Set passThroughCache = new HashSet<>(); + private final Set passThroughCache = new HashSet<>(); //~ Constructors ----------------------------------------------------------- @@ -135,7 +138,7 @@ private interface Procedure { void exec(); } - private void applyGenerator(GeneratorTask task, Procedure proc) { + private void applyGenerator(@Nullable GeneratorTask task, Procedure proc) { GeneratorTask applying = this.applying; this.applying = task; try { @@ -160,7 +163,9 @@ private void clearProcessed(RelSet set) { if (subset.resetTaskState() || explored) { Collection parentRels = subset.getParentRels(); for (RelNode parentRel : parentRels) { - clearProcessed(planner.getSet(parentRel)); + RelSet parentRelSet = + assertNonNull(planner.getSet(parentRel), () -> "no set found for " + parentRel); + clearProcessed(parentRelSet); } if (subset == planner.root) { tasks.push(new OptimizeGroup(subset, planner.infCost)); 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 50e2715e1d64..375de12c9dd0 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 @@ -61,7 +61,13 @@ import com.google.common.collect.Multimap; import org.apiguardian.api.API; +import org.checkerframework.checker.nullness.qual.EnsuresNonNull; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.PolyNull; +import org.checkerframework.checker.nullness.qual.RequiresNonNull; +import org.checkerframework.dataflow.qual.Pure; import java.io.PrintWriter; import java.io.StringWriter; @@ -74,10 +80,14 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * VolcanoPlanner optimizes queries by transforming expressions selectively * according to a dynamic programming algorithm. @@ -86,7 +96,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { //~ Instance fields -------------------------------------------------------- - protected RelSubset root; + protected @MonotonicNonNull RelSubset root; /** * Operands that apply to a given class of {@link RelNode}. @@ -139,7 +149,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { /** * A driver to manage rule and rule matches. */ - RuleDriver ruleDriver; + @NonNull RuleDriver ruleDriver; /** * Holds the currently registered RelTraitDefs. @@ -148,9 +158,9 @@ public class VolcanoPlanner extends AbstractRelOptPlanner { private int nextSetId = 0; - private RelNode originalRoot; + private @MonotonicNonNull RelNode originalRoot; - private Convention rootConvention; + private @Nullable Convention rootConvention; /** * Whether the planner can accept new rules. @@ -216,8 +226,9 @@ public VolcanoPlanner(Context externalContext) { /** * Creates a {@code VolcanoPlanner} with a given cost factory. */ + @SuppressWarnings("method.invocation.invalid") public VolcanoPlanner(@Nullable RelOptCostFactory costFactory, - Context externalContext) { + @Nullable Context externalContext) { super(costFactory == null ? VolcanoCost.FACTORY : costFactory, externalContext); this.zeroCost = this.costFactory.makeZeroCost(); @@ -228,6 +239,7 @@ public VolcanoPlanner(@Nullable RelOptCostFactory costFactory, initRuleQueue(); } + @EnsuresNonNull("ruleDriver") private void initRuleQueue() { if (topDownOpt) { ruleDriver = new TopDownRuleDriver(this); @@ -272,7 +284,8 @@ public void setRoot(RelNode rel) { ensureRootConverters(); } - public RelNode getRoot() { + @Pure + public @Nullable RelNode getRoot() { return root; } @@ -301,6 +314,9 @@ protected void registerMaterializations() { return; } + assert root != null : "root"; + assert originalRoot != null : "originalRoot"; + // Register rels using materialized views. final List>> materializationUses = RelOptMaterializations.useMaterializedViews(originalRoot, materializations); @@ -349,7 +365,7 @@ protected void registerMaterializations() { * @return Equivalence set that expression belongs to, or null if it is not * registered */ - public RelSet getSet(RelNode rel) { + public @Nullable RelSet getSet(RelNode rel) { assert rel != null : "pre: rel != null"; final RelSubset subset = getSubset(rel); if (subset != null) { @@ -505,6 +521,7 @@ public RelOptPlanner chooseDelegate() { * query */ public RelNode findBestExp() { + assert root != null : "root must not be null"; ensureRootConverters(); registerMaterializations(); @@ -551,6 +568,7 @@ private void registerMetadataRels() { * in the plan where explicit converters are required; elsewhere, a consumer * will be asking for the result in a particular convention, but the root has * no consumers. */ + @RequiresNonNull("root") void ensureRootConverters() { final Set subsets = new HashSet<>(); for (RelNode rel : root.getRels()) { @@ -572,7 +590,7 @@ void ensureRootConverters() { public RelSubset register( RelNode rel, - RelNode equivRel) { + @Nullable RelNode equivRel) { assert !isRegistered(rel) : "pre: isRegistered(rel)"; final RelSet set; if (equivRel == null) { @@ -595,7 +613,7 @@ public RelSubset ensureRegistered(RelNode rel, @Nullable RelNode equivRel) { final RelSubset subset = getSubset(rel); if (subset != null) { if (equivRel != null) { - final RelSubset equivSubset = getSubset(equivRel); + final RelSubset equivSubset = getSubsetNonNull(equivRel); if (subset.set != equivSubset.set) { merge(equivSubset.set, subset.set); } @@ -618,11 +636,12 @@ public RelSubset ensureRegistered(RelNode rel, @Nullable RelNode equivRel) { * Checks internal consistency. */ protected boolean isValid(Litmus litmus) { - if (this.getRoot() == null) { + RelNode root = getRoot(); + if (root == null) { return true; } - RelMetadataQuery metaQuery = this.getRoot().getCluster().getMetadataQuerySupplier().get(); + RelMetadataQuery metaQuery = root.getCluster().getMetadataQuerySupplier().get(); for (RelSet set : allSets) { if (set.equivalentSet != null) { return litmus.fail("set [{}] has been merged: it should not be in the list", set); @@ -644,7 +663,7 @@ protected boolean isValid(Litmus litmus) { // Make sure bestCost is up-to-date try { RelOptCost bestCost = getCost(subset.best, metaQuery); - if (!subset.bestCost.equals(bestCost)) { + if (!Objects.equals(subset.bestCost, bestCost)) { return litmus.fail("RelSubset [" + subset + "] has wrong best cost " + subset.bestCost + ". Correct cost is " + bestCost); @@ -657,7 +676,7 @@ protected boolean isValid(Litmus litmus) { for (RelNode rel : subset.getRels()) { try { RelOptCost relCost = getCost(rel, metaQuery); - if (relCost.isLt(subset.bestCost)) { + if (relCost != null && relCost.isLt(subset.bestCost)) { return litmus.fail("rel [{}] has lower cost {} than " + "best cost {} of subset [{}]", rel, relCost, subset.bestCost, subset); @@ -704,12 +723,19 @@ public void setNoneConventionHasInfiniteCost(boolean infinite) { return costFactory.makeInfiniteCost(); } RelOptCost cost = mq.getNonCumulativeCost(rel); + if (cost == null) { + return null; + } if (!zeroCost.isLt(cost)) { // cost must be positive, so nudge it cost = costFactory.makeTinyCost(); } for (RelNode input : rel.getInputs()) { - cost = cost.plus(getCost(input, mq)); + RelOptCost inputCost = getCost(input, mq); + if (inputCost == null) { + return null; + } + cost = cost.plus(inputCost); } return cost; } @@ -720,7 +746,7 @@ public void setNoneConventionHasInfiniteCost(boolean infinite) { * @param rel Relational expression * @return Subset it belongs to, or null if it is not registered */ - public RelSubset getSubset(RelNode rel) { + public @Nullable RelSubset getSubset(RelNode rel) { assert rel != null : "pre: rel != null"; if (rel instanceof RelSubset) { return (RelSubset) rel; @@ -729,7 +755,19 @@ public RelSubset getSubset(RelNode rel) { } } - public RelSubset getSubset(RelNode rel, RelTraitSet traits) { + /** + * Returns the subset that a relational expression belongs to. + * + * @param rel Relational expression + * @return Subset it belongs to, or null if it is not registered + * @throws AssertionError in case subset is not found + */ + @API(since = "1.26", status = API.Status.EXPERIMENTAL) + public RelSubset getSubsetNonNull(RelNode rel) { + return assertNonNull(getSubset(rel), () -> "Subset is not found for " + rel); + } + + public @Nullable RelSubset getSubset(RelNode rel, RelTraitSet traits) { if ((rel instanceof RelSubset) && (rel.getTraitSet().equals(traits))) { return (RelSubset) rel; } @@ -740,7 +778,7 @@ public RelSubset getSubset(RelNode rel, RelTraitSet traits) { return set.getSubset(traits); } - RelNode changeTraitsUsingConverters( + @Nullable RelNode changeTraitsUsingConverters( RelNode rel, RelTraitSet toTraits) { final RelTraitSet fromTraits = rel.getTraitSet(); @@ -773,18 +811,18 @@ RelNode changeTraitsUsingConverters( continue; } - rel = + RelNode convertedRel = traitDef.convert( this, converted, toTrait, allowInfiniteCostConverters); - if (rel != null) { - assert rel.getTraitSet().getTrait(traitDef).satisfies(toTrait); - register(rel, converted); + if (convertedRel != null) { + assert castNonNull(convertedRel.getTraitSet().getTrait(traitDef)).satisfies(toTrait); + register(convertedRel, converted); } - converted = rel; + converted = convertedRel; } // make sure final converted traitset subsumes what was required @@ -849,7 +887,7 @@ public String toDot() { * @param rel Relational expression */ void rename(RelNode rel) { - String oldDigest = null; + String oldDigest = ""; if (LOGGER.isTraceEnabled()) { oldDigest = rel.getDigest(); } @@ -868,7 +906,7 @@ void rename(RelNode rel) { mapDigestToRel.put(newDigest, equivRel); checkPruned(equivRel, rel); - RelSubset equivRelSubset = getSubset(equivRel); + RelSubset equivRelSubset = getSubsetNonNull(equivRel); // Remove back-links from children. for (RelNode input : rel.getInputs()) { @@ -882,7 +920,7 @@ void rename(RelNode rel) { assert subset != null; boolean existed = subset.set.rels.remove(rel); assert existed : "rel was not known to its set"; - final RelSubset equivSubset = getSubset(equivRel); + final RelSubset equivSubset = getSubsetNonNull(equivRel); for (RelSubset s : subset.set.subsets) { if (s.best == rel) { Set activeSet = new HashSet<>(); @@ -948,6 +986,7 @@ private void checkPruned(RelNode rel, RelNode duplicateRel) { /** * Find the new root subset in case the root is merged with another subset. */ + @RequiresNonNull("root") void canonize() { root = canonize(root); } @@ -961,10 +1000,10 @@ void canonize() { * @return Leader of subset's equivalence class */ private RelSubset canonize(final RelSubset subset) { - if (subset.set.equivalentSet == null) { + RelSet set = subset.set; + if (set.equivalentSet == null) { return subset; } - RelSet set = subset.set; do { set = set.equivalentSet; } while (set.equivalentSet != null); @@ -1046,6 +1085,10 @@ private RelSet merge(RelSet set, RelSet set2) { // Merge. set.mergeWith(this, set2); + if (root == null) { + throw new IllegalStateException("root must not be null"); + } + // Was the set we merged with the root? If so, the result is the new // root. if (set2 == getSet(root)) { @@ -1070,14 +1113,14 @@ static RelSet equivRoot(RelSet s) { } /** Moves forward two links, checking for a cycle at each. */ - private static RelSet forward2(RelSet s, RelSet p) { + private static @Nullable RelSet forward2(RelSet s, @Nullable RelSet p) { p = forward1(s, p); p = forward1(s, p); return p; } /** Moves forward one link, checking for a cycle. */ - private static RelSet forward1(RelSet s, RelSet p) { + private static @Nullable RelSet forward1(RelSet s, @Nullable RelSet p) { if (p != null) { p = p.equivalentSet; if (p == s) { @@ -1100,7 +1143,7 @@ private static RelSet forward1(RelSet s, RelSet p) { */ private RelSubset registerImpl( RelNode rel, - RelSet set) { + @Nullable RelSet set) { if (rel instanceof RelSubset) { return registerSubset(set, (RelSubset) rel); } @@ -1133,10 +1176,10 @@ private RelSubset registerImpl( rel = rel.onRegister(this); // Record its provenance. (Rule call may be null.) - if (ruleCallStack.isEmpty()) { + final VolcanoRuleCall ruleCall = ruleCallStack.peek(); + if (ruleCall == null) { provenanceMap.put(rel, Provenance.EMPTY); } else { - final VolcanoRuleCall ruleCall = ruleCallStack.peek(); provenanceMap.put( rel, new RuleProvenance( @@ -1152,7 +1195,8 @@ private RelSubset registerImpl( if (equivExp == null) { // do nothing } else if (equivExp == rel) { - return getSubset(rel); + // The same rel is already registered, so return its subset + return getSubsetNonNull(equivExp); } else { assert RelOptUtil.equal( "left", equivExp.getRowType(), @@ -1164,14 +1208,14 @@ private RelSubset registerImpl( if (equivSet != null) { LOGGER.trace( "Register: rel#{} is equivalent to {}", rel.getId(), equivExp); - return registerSubset(set, getSubset(equivExp)); + return registerSubset(set, getSubsetNonNull(equivExp)); } } // Converters are in the same set as their children. if (rel instanceof Converter) { final RelNode input = ((Converter) rel).getInput(); - final RelSet childSet = getSet(input); + final RelSet childSet = castNonNull(getSet(input)); if ((set != null) && (set != childSet) && (set.equivalentSet == null)) { @@ -1196,7 +1240,7 @@ private RelSubset registerImpl( // There is already an equivalent expression. Use that // one, and forget about this one. - return getSubset(equivRel); + return getSubsetNonNull(equivRel); } } } else { @@ -1279,7 +1323,7 @@ private RelSubset addRelToSet(RelNode rel, RelSet set) { } private RelSubset registerSubset( - RelSet set, + @Nullable RelSet set, RelSubset subset) { if ((set != subset.set) && (set != null) @@ -1342,7 +1386,7 @@ public long getRelMetadataTimestamp(RelNode rel) { * @param plan Plan * @return Normalized plan */ - public static String normalizePlan(String plan) { + public static @PolyNull String normalizePlan(@PolyNull String plan) { if (plan == null) { return null; } @@ -1435,7 +1479,7 @@ protected RelOptCost upperBoundForInputs( if (!upperBound.isInfinite()) { RelOptCost rootCost = mExpr.getCluster() .getMetadataQuery().getNonCumulativeCost(mExpr); - if (!rootCost.isInfinite()) { + if (rootCost != null && !rootCost.isInfinite()) { return upperBound.minus(rootCost); } } diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRuleCall.java b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRuleCall.java index b5e61e3cb541..f924baa4baf1 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRuleCall.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRuleCall.java @@ -30,6 +30,8 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -39,6 +41,9 @@ import java.util.Set; import java.util.stream.Collectors; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * VolcanoRuleCall implements the {@link RelOptRuleCall} interface * for VolcanoPlanner. @@ -51,7 +56,7 @@ public class VolcanoRuleCall extends RelOptRuleCall { /** * List of {@link RelNode} generated by this call. For debugging purposes. */ - private List generatedRelList; + private @Nullable List generatedRelList; //~ Constructors ----------------------------------------------------------- @@ -231,7 +236,7 @@ protected void onMatch() { volcanoPlanner.ruleCallStack.pop(); } - if (LOGGER.isDebugEnabled()) { + if (generatedRelList != null) { if (generatedRelList.isEmpty()) { LOGGER.debug("call#{} generated 0 successors.", id); } else { @@ -263,7 +268,7 @@ protected void onMatch() { void match(RelNode rel) { assert getOperand0().matches(rel) : "precondition"; final int solve = 0; - int operandOrdinal = getOperand0().solveOrder[solve]; + int operandOrdinal = castNonNull(getOperand0().solveOrder)[solve]; this.rels[operandOrdinal] = rel; matchRecurse(solve + 1); } @@ -285,8 +290,9 @@ private void matchRecurse(int solve) { onMatch(); } } else { - final int operandOrdinal = operand0.solveOrder[solve]; - final int previousOperandOrdinal = operand0.solveOrder[solve - 1]; + final int[] solveOrder = castNonNull(operand0.solveOrder); + final int operandOrdinal = solveOrder[solve]; + final int previousOperandOrdinal = solveOrder[solve - 1]; boolean ascending = operandOrdinal < previousOperandOrdinal; final RelOptRuleOperand previousOperand = operands.get(previousOperandOrdinal); @@ -304,10 +310,12 @@ private void matchRecurse(int solve) { + previousOperand.getMatchedClass().getSimpleName()); } parentOperand = operand; - final RelSubset subset = volcanoPlanner.getSubset(previous); + final RelSubset subset = volcanoPlanner.getSubsetNonNull(previous); successors = subset.getParentRels(); } else { - parentOperand = operand.getParent(); + parentOperand = assertNonNull( + operand.getParent(), + () -> "operand.getParent() for " + operand); final RelNode parentRel = rels[parentOperand.ordinalInRule]; final List inputs = parentRel.getInputs(); // if the child is unordered, then add all rels in all input subsets to the successors list diff --git a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java index 9e4e1f101452..877968d66392 100644 --- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java +++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java @@ -34,7 +34,6 @@ import org.apache.calcite.jdbc.CalciteSchema; import org.apache.calcite.jdbc.CalciteSchema.LatticeEntry; import org.apache.calcite.linq4j.Linq4j; -import org.apache.calcite.linq4j.Nullness; import org.apache.calcite.linq4j.Ord; import org.apache.calcite.linq4j.Queryable; import org.apache.calcite.linq4j.function.Function1; diff --git a/core/src/main/java/org/apache/calcite/prepare/Prepare.java b/core/src/main/java/org/apache/calcite/prepare/Prepare.java index 66cf6622e548..956fd71b14a9 100644 --- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java +++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java @@ -77,6 +77,8 @@ import java.util.List; import java.util.Objects; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Abstract base for classes that implement * the process of preparing and executing SQL expressions. @@ -144,8 +146,9 @@ protected RelRoot optimize(RelRoot root, for (Materialization materialization : materializations) { List qualifiedTableName = materialization.materializedTable.path(); materializationList.add( - new RelOptMaterialization(materialization.tableRel, - materialization.queryRel, + new RelOptMaterialization( + castNonNull(materialization.tableRel), + castNonNull(materialization.queryRel), materialization.starRelOptTable, qualifiedTableName)); } @@ -391,7 +394,7 @@ public interface CatalogReader @Override PreparingTable getTable(List names); - ThreadLocal THREAD_LOCAL = new ThreadLocal<>(); + ThreadLocal<@Nullable CatalogReader> THREAD_LOCAL = new ThreadLocal<>(); } /** Definition of a table, for the purposes of the validator and planner. */ @@ -485,7 +488,7 @@ public PreparedExplain( public String getCode() { if (root == null) { - return RelOptUtil.dumpType(rowType); + return rowType == null ? "rowType is null" : RelOptUtil.dumpType(rowType); } else { return RelOptUtil.dumpPlan("", root.rel, format, detailLevel); } diff --git a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java index a502b70fe69b..592dd506955d 100644 --- a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java +++ b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java @@ -480,7 +480,7 @@ public static MySchemaPlus create(Path path) { return schema.isMutable(); } - @Override public T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { return null; } diff --git a/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java b/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java index 3e69e789502a..01fa24e54ba4 100644 --- a/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java +++ b/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java @@ -43,6 +43,7 @@ import org.apiguardian.api.API; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; import org.slf4j.Logger; import java.util.ArrayList; @@ -125,6 +126,7 @@ public final RelOptCluster getCluster() { return cluster; } + @Pure public final @Nullable Convention getConvention() { return traitSet.getTrait(ConventionTraitDef.INSTANCE); } @@ -353,11 +355,11 @@ public final RelDigest getRelDigest() { * @see #deepHashCode() */ @API(since = "1.25", status = API.Status.MAINTAINED) - public boolean deepEquals(Object obj) { + public boolean deepEquals(@Nullable Object obj) { if (this == obj) { return true; } - if (this.getClass() != obj.getClass()) { + if (obj == null || this.getClass() != obj.getClass()) { return false; } AbstractRelNode that = (AbstractRelNode) obj; @@ -386,7 +388,7 @@ public boolean deepEquals(Object obj) { /** * Compute hash code for RelNode digest. * - * @see #deepEquals(Object) + * @see RelNode#deepEquals(Object) */ @API(since = "1.25", status = API.Status.MAINTAINED) public int deepHashCode() { @@ -469,7 +471,8 @@ private static final class RelDigestWriter implements RelWriter { @Nullable String digest = null; - @Override public void explain(final RelNode rel, final List> valueList) { + @Override public void explain(final RelNode rel, + final List> valueList) { throw new IllegalStateException("Should not be called for computing digest"); } diff --git a/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java b/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java index bab96ab019e6..2b830270fcce 100644 --- a/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java +++ b/core/src/main/java/org/apache/calcite/rel/RelCollationTraitDef.java @@ -22,6 +22,8 @@ import org.apache.calcite.rel.core.Sort; import org.apache.calcite.rel.logical.LogicalSort; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Definition of the ordering trait. * @@ -59,7 +61,7 @@ public RelCollation getDefault() { return RelCollations.EMPTY; } - public RelNode convert( + public @Nullable RelNode convert( RelOptPlanner planner, RelNode rel, RelCollation toCollation, diff --git a/core/src/main/java/org/apache/calcite/rel/RelDistributionTraitDef.java b/core/src/main/java/org/apache/calcite/rel/RelDistributionTraitDef.java index 72dd253f7365..acfaaf52dfbe 100644 --- a/core/src/main/java/org/apache/calcite/rel/RelDistributionTraitDef.java +++ b/core/src/main/java/org/apache/calcite/rel/RelDistributionTraitDef.java @@ -22,6 +22,8 @@ import org.apache.calcite.rel.core.Exchange; import org.apache.calcite.rel.logical.LogicalExchange; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Definition of the distribution trait. * @@ -48,7 +50,7 @@ public RelDistribution getDefault() { return RelDistributions.ANY; } - public RelNode convert(RelOptPlanner planner, RelNode rel, + public @Nullable RelNode convert(RelOptPlanner planner, RelNode rel, RelDistribution toDistribution, boolean allowInfiniteCostConverters) { if (toDistribution == RelDistributions.ANY) { return rel; diff --git a/core/src/main/java/org/apache/calcite/rel/RelNode.java b/core/src/main/java/org/apache/calcite/rel/RelNode.java index bc0562459233..2babec8e72d7 100644 --- a/core/src/main/java/org/apache/calcite/rel/RelNode.java +++ b/core/src/main/java/org/apache/calcite/rel/RelNode.java @@ -32,6 +32,7 @@ import org.apache.calcite.util.Litmus; import org.apiguardian.api.API; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.List; @@ -277,7 +278,8 @@ default String getDigest() { * @return Whether the 2 RelNodes are equivalent or have the same digest. * @see #deepHashCode() */ - boolean deepEquals(Object obj); + @EnsuresNonNullIf(expression = "#1", result = true) + boolean deepEquals(@Nullable Object obj); /** * Compute deep hash code for RelNode digest. diff --git a/core/src/main/java/org/apache/calcite/rel/convert/Converter.java b/core/src/main/java/org/apache/calcite/rel/convert/Converter.java index 2639f21e1f06..19b1c61bce0e 100644 --- a/core/src/main/java/org/apache/calcite/rel/convert/Converter.java +++ b/core/src/main/java/org/apache/calcite/rel/convert/Converter.java @@ -20,6 +20,8 @@ import org.apache.calcite.plan.RelTraitSet; import org.apache.calcite.rel.RelNode; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * A relational expression implements the interface Converter to * indicate that it converts a physical attribute, or @@ -64,7 +66,7 @@ public interface Converter extends RelNode { * * @return trait which this converter modifies */ - RelTraitDef getTraitDef(); + @Nullable RelTraitDef getTraitDef(); /** * Returns the sole input relational expression. diff --git a/core/src/main/java/org/apache/calcite/rel/convert/ConverterImpl.java b/core/src/main/java/org/apache/calcite/rel/convert/ConverterImpl.java index 310cf6290736..5899dc07f4d4 100644 --- a/core/src/main/java/org/apache/calcite/rel/convert/ConverterImpl.java +++ b/core/src/main/java/org/apache/calcite/rel/convert/ConverterImpl.java @@ -25,6 +25,8 @@ import org.apache.calcite.rel.SingleRel; import org.apache.calcite.rel.metadata.RelMetadataQuery; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Abstract implementation of {@link Converter}. */ @@ -33,7 +35,7 @@ public abstract class ConverterImpl extends SingleRel //~ Instance fields -------------------------------------------------------- protected RelTraitSet inTraits; - protected final RelTraitDef traitDef; + protected final @Nullable RelTraitDef traitDef; //~ Constructors ----------------------------------------------------------- @@ -47,7 +49,7 @@ public abstract class ConverterImpl extends SingleRel */ protected ConverterImpl( RelOptCluster cluster, - RelTraitDef traitDef, + @Nullable RelTraitDef traitDef, RelTraitSet traits, RelNode child) { super(cluster, traits, child); @@ -75,7 +77,7 @@ public RelTraitSet getInputTraits() { return inTraits; } - public RelTraitDef getTraitDef() { + public @Nullable RelTraitDef getTraitDef() { return traitDef; } diff --git a/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java b/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java index ad81786c4128..2a180afcd3f4 100644 --- a/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java +++ b/core/src/main/java/org/apache/calcite/rel/convert/ConverterRule.java @@ -33,6 +33,8 @@ import java.util.function.Function; import java.util.function.Predicate; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Abstract base class for a rule which converts from one calling convention to * another without changing semantics. @@ -59,7 +61,7 @@ protected ConverterRule(Config config) { // Most sub-classes are concerned with converting one convention to // another, and for them, the "out" field is a convenient short-cut. this.out = outTrait instanceof Convention ? (Convention) outTrait - : null; + : castNonNull(null); } /** @@ -126,7 +128,7 @@ public ConverterRule(Class clazz, return (Convention) outTrait; } - public @Nullable RelTrait getOutTrait() { + public RelTrait getOutTrait() { return outTrait; } @@ -146,8 +148,7 @@ private static String createDescription(String descriptionPrefix, /** Converts a relational expression to the target trait(s) of this rule. * - *

Returns null if conversion is not possible. - * @return*/ + *

Returns null if conversion is not possible. */ public abstract @Nullable RelNode convert(RelNode rel); /** diff --git a/core/src/main/java/org/apache/calcite/rel/core/Filter.java b/core/src/main/java/org/apache/calcite/rel/core/Filter.java index 0f961e87f2fc..5fa425a1cf76 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/Filter.java +++ b/core/src/main/java/org/apache/calcite/rel/core/Filter.java @@ -36,6 +36,7 @@ import org.apache.calcite.util.Litmus; import org.apiguardian.api.API; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.List; @@ -158,7 +159,8 @@ public RelWriter explainTerms(RelWriter pw) { } @API(since = "1.24", status = API.Status.INTERNAL) - protected boolean deepEquals0(Object obj) { + @EnsuresNonNullIf(expression = "#1", result = true) + protected boolean deepEquals0(@Nullable Object obj) { if (this == obj) { return true; } diff --git a/core/src/main/java/org/apache/calcite/rel/core/Join.java b/core/src/main/java/org/apache/calcite/rel/core/Join.java index 5f50782c8a62..f0881c7e1efc 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/Join.java +++ b/core/src/main/java/org/apache/calcite/rel/core/Join.java @@ -42,6 +42,7 @@ import com.google.common.collect.ImmutableSet; import org.apiguardian.api.API; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Collections; @@ -221,7 +222,8 @@ public static double estimateJoinedRows( } @API(since = "1.24", status = API.Status.INTERNAL) - protected boolean deepEquals0(Object obj) { + @EnsuresNonNullIf(expression = "#1", result = true) + protected boolean deepEquals0(@Nullable Object obj) { if (this == obj) { return true; } diff --git a/core/src/main/java/org/apache/calcite/rel/core/Match.java b/core/src/main/java/org/apache/calcite/rel/core/Match.java index 7ababd1eac5d..b9c5e77c67f4 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/Match.java +++ b/core/src/main/java/org/apache/calcite/rel/core/Match.java @@ -71,7 +71,7 @@ public abstract class Match extends SingleRel { protected final ImmutableMap> subsets; protected final ImmutableBitSet partitionKeys; protected final RelCollation orderKeys; - protected final RexNode interval; + protected final @Nullable RexNode interval; //~ Constructors ----------------------------------------------- @@ -100,7 +100,7 @@ protected Match(RelOptCluster cluster, RelTraitSet traitSet, RelNode input, Map patternDefinitions, Map measures, RexNode after, Map> subsets, boolean allRows, ImmutableBitSet partitionKeys, RelCollation orderKeys, - RexNode interval) { + @Nullable RexNode interval) { super(cluster, traitSet, input); this.rowType = Objects.requireNonNull(rowType); this.pattern = Objects.requireNonNull(pattern); @@ -188,7 +188,7 @@ public RelCollation getOrderKeys() { return orderKeys; } - public RexNode getInterval() { + public @Nullable RexNode getInterval() { return interval; } diff --git a/core/src/main/java/org/apache/calcite/rel/core/Project.java b/core/src/main/java/org/apache/calcite/rel/core/Project.java index 35593218761a..f5c5f6d2a165 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/Project.java +++ b/core/src/main/java/org/apache/calcite/rel/core/Project.java @@ -48,6 +48,7 @@ import com.google.common.collect.Lists; import org.apiguardian.api.API; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.HashSet; @@ -295,6 +296,7 @@ public RelWriter explainTerms(RelWriter pw) { } @API(since = "1.24", status = API.Status.INTERNAL) + @EnsuresNonNullIf(expression = "#1", result = true) protected boolean deepEquals0(@Nullable Object obj) { if (this == obj) { return true; diff --git a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java index ca4333647814..37034c9301ad 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java +++ b/core/src/main/java/org/apache/calcite/rel/core/RelFactories.java @@ -72,6 +72,8 @@ import java.util.SortedSet; import javax.annotation.Nonnull; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; + /** * Contains factory interface and default implementation for creating various * rel nodes. @@ -527,7 +529,7 @@ private static class TableFunctionScanFactoryImpl operator.getRowTypeInference(); final RelDataType rowType = rowTypeInference.inferReturnType(callBinding); return LogicalTableFunctionScan.create(cluster, inputs, call, - elementType, rowType, columnMappings); + elementType, assertNonNull(rowType, "rowType"), columnMappings); } } diff --git a/core/src/main/java/org/apache/calcite/rel/core/TableFunctionScan.java b/core/src/main/java/org/apache/calcite/rel/core/TableFunctionScan.java index c479dc8e60c4..2ee644df9d65 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/TableFunctionScan.java +++ b/core/src/main/java/org/apache/calcite/rel/core/TableFunctionScan.java @@ -79,7 +79,7 @@ protected TableFunctionScan( List inputs, RexNode rexCall, @Nullable Type elementType, - @Nullable RelDataType rowType, + RelDataType rowType, @Nullable Set columnMappings) { super(cluster, traitSet); this.rexCall = rexCall; diff --git a/core/src/main/java/org/apache/calcite/rel/core/TableModify.java b/core/src/main/java/org/apache/calcite/rel/core/TableModify.java index cad1e4366e24..162eb2df8157 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/TableModify.java +++ b/core/src/main/java/org/apache/calcite/rel/core/TableModify.java @@ -37,8 +37,6 @@ import com.google.common.base.Preconditions; -import org.checkerframework.checker.nullness.qual.Nullable; - import java.util.List; import java.util.Objects; 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 b27a40d63ea0..7f6dd3599bc2 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 @@ -39,8 +39,6 @@ import com.google.common.collect.ImmutableList; -import org.checkerframework.checker.nullness.qual.Nullable; - import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -93,7 +91,7 @@ protected TableScan(RelInput input) { return table.getRowCount(); } - @Override public @Nullable RelOptTable getTable() { + @Override public RelOptTable getTable() { return table; } diff --git a/core/src/main/java/org/apache/calcite/rel/core/TableSpool.java b/core/src/main/java/org/apache/calcite/rel/core/TableSpool.java index 75be44b0650c..cb7ec14ba0d4 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/TableSpool.java +++ b/core/src/main/java/org/apache/calcite/rel/core/TableSpool.java @@ -23,8 +23,6 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.RelWriter; -import org.checkerframework.checker.nullness.qual.Nullable; - import java.util.Objects; /** @@ -44,7 +42,7 @@ protected TableSpool(RelOptCluster cluster, RelTraitSet traitSet, this.table = Objects.requireNonNull(table); } - public @Nullable RelOptTable getTable() { + public RelOptTable getTable() { return table; } diff --git a/core/src/main/java/org/apache/calcite/rel/core/Window.java b/core/src/main/java/org/apache/calcite/rel/core/Window.java index b410590fedba..d6d90a54dc92 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/Window.java +++ b/core/src/main/java/org/apache/calcite/rel/core/Window.java @@ -45,7 +45,9 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.initialization.qual.UnderInitialization; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.RequiresNonNull; import java.util.AbstractList; import java.util.List; @@ -245,7 +247,10 @@ public String toString() { return digest; } - private String computeString() { + @RequiresNonNull({"keys", "orderKeys", "lowerBound", "upperBound", "aggCalls"}) + private String computeString( + @UnderInitialization Group this + ) { final StringBuilder buf = new StringBuilder("window("); final int i = buf.length(); if (!keys.isEmpty()) { diff --git a/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java b/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java index bca01f99fb63..c6ec667268d4 100644 --- a/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java +++ b/core/src/main/java/org/apache/calcite/rel/externalize/RelJson.java @@ -65,7 +65,6 @@ import com.google.common.collect.ImmutableList; import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.checker.nullness.qual.PolyNull; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; diff --git a/core/src/main/java/org/apache/calcite/rel/hint/HintStrategy.java b/core/src/main/java/org/apache/calcite/rel/hint/HintStrategy.java index 7670f783fee3..95c377f6d734 100644 --- a/core/src/main/java/org/apache/calcite/rel/hint/HintStrategy.java +++ b/core/src/main/java/org/apache/calcite/rel/hint/HintStrategy.java @@ -21,8 +21,9 @@ import com.google.common.collect.ImmutableSet; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Objects; -import javax.annotation.Nullable; /** * Represents a hint strategy entry of {@link HintStrategyTable}. @@ -47,7 +48,7 @@ public class HintStrategy { //~ Instance fields -------------------------------------------------------- public final HintPredicate predicate; - public final HintOptionChecker hintOptionChecker; + public final @Nullable HintOptionChecker hintOptionChecker; public final ImmutableSet excludedRules; public final ImmutableSet converterRules; @@ -55,7 +56,7 @@ public class HintStrategy { private HintStrategy( HintPredicate predicate, - HintOptionChecker hintOptionChecker, + @Nullable HintOptionChecker hintOptionChecker, ImmutableSet excludedRules, ImmutableSet converterRules) { this.predicate = predicate; @@ -79,8 +80,7 @@ public static Builder builder(HintPredicate hintPredicate) { /** Builder for {@link HintStrategy}. */ public static class Builder { private final HintPredicate predicate; - @Nullable - private HintOptionChecker optionChecker; + private @Nullable HintOptionChecker optionChecker; private ImmutableSet excludedRules; private ImmutableSet converterRules; diff --git a/core/src/main/java/org/apache/calcite/rel/hint/HintStrategyTable.java b/core/src/main/java/org/apache/calcite/rel/hint/HintStrategyTable.java index 3d8453fb622e..7f3f8deb65a5 100644 --- a/core/src/main/java/org/apache/calcite/rel/hint/HintStrategyTable.java +++ b/core/src/main/java/org/apache/calcite/rel/hint/HintStrategyTable.java @@ -34,6 +34,8 @@ import java.util.Set; import java.util.stream.Collectors; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; + /** * A collection of {@link HintStrategy}s. * @@ -86,7 +88,7 @@ public List apply(List hints, RelNode rel) { private boolean canApply(RelHint hint, RelNode rel) { final Key key = Key.of(hint.hintName); - assert this.strategies.containsKey(key); + assert this.strategies.containsKey(key) : "hint " + hint.hintName + " must be present"; return this.strategies.get(key).predicate.apply(hint, rel); } @@ -106,7 +108,7 @@ public boolean validateHint(RelHint hint) { return false; } final HintStrategy strategy = strategies.get(key); - if (strategy.hintOptionChecker != null) { + if (strategy != null && strategy.hintOptionChecker != null) { return strategy.hintOptionChecker.checkOptions(hint, this.errorHandler); } return true; @@ -122,7 +124,7 @@ public boolean isRuleExcluded(Hintable hintable, RelOptRule rule) { for (RelHint hint : hints) { final Key key = Key.of(hint.hintName); - assert this.strategies.containsKey(key); + assert this.strategies.containsKey(key) : "hint " + hint.hintName + " must be present"; final HintStrategy strategy = strategies.get(key); if (strategy.excludedRules.contains(rule)) { return isDesiredConversionPossible(strategy.converterRules, hintable); @@ -156,7 +158,7 @@ public static Builder builder() { * Key used to keep the strategies which ignores the case sensitivity. */ private static class Key { - private String name; + private final String name; private Key(String name) { this.name = name; } @@ -185,7 +187,7 @@ static Key of(String name) { * Builder for {@code HintStrategyTable}. */ public static class Builder { - private Map strategies; + private final Map strategies; private Litmus errorHandler; private Builder() { @@ -230,8 +232,8 @@ public static class HintErrorLogger implements Litmus { public static final HintErrorLogger INSTANCE = new HintErrorLogger(); - public boolean fail(@Nullable String message, Object... args) { - LOGGER.warn(message, args); + public boolean fail(@Nullable String message, @Nullable Object... args) { + LOGGER.warn(assertNonNull(message, "message"), args); return false; } @@ -239,7 +241,7 @@ public boolean succeed() { return true; } - public boolean check(boolean condition, @Nullable String message, Object... args) { + public boolean check(boolean condition, @Nullable String message, @Nullable Object... args) { if (condition) { return succeed(); } else { diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java index 740469bda496..6785132220e5 100644 --- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java +++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalFilter.java @@ -35,6 +35,8 @@ import com.google.common.collect.ImmutableSet; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Objects; import java.util.Set; @@ -136,7 +138,7 @@ public LogicalFilter copy(RelTraitSet traitSet, RelNode input, .itemIf("variablesSet", variablesSet, !variablesSet.isEmpty()); } - @Override public boolean deepEquals(Object obj) { + @Override public boolean deepEquals(@Nullable Object obj) { return deepEquals0(obj) && variablesSet.equals(((LogicalFilter) obj).variablesSet); } diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java index baf87ec454b8..bb2f114f195e 100644 --- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java +++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalJoin.java @@ -33,6 +33,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -191,7 +193,7 @@ public RelWriter explainTerms(RelWriter pw) { .itemIf("semiJoinDone", semiJoinDone, semiJoinDone); } - @Override public boolean deepEquals(Object obj) { + @Override public boolean deepEquals(@Nullable Object obj) { if (this == obj) { return true; } diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java index 87f5df225d8d..e7030f5aabcf 100644 --- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java +++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalProject.java @@ -36,6 +36,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -134,10 +136,10 @@ public static LogicalProject create(final RelNode input, List hints, @Override public RelNode withHints(List hintList) { return new LogicalProject(getCluster(), traitSet, hintList, - input, getProjects(), rowType); + input, getProjects(), getRowType()); } - @Override public boolean deepEquals(Object obj) { + @Override public boolean deepEquals(@Nullable Object obj) { return deepEquals0(obj); } diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/BuiltInMetadata.java b/core/src/main/java/org/apache/calcite/rel/metadata/BuiltInMetadata.java index 9d95ce816c34..273f7a2f28eb 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/BuiltInMetadata.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/BuiltInMetadata.java @@ -366,12 +366,12 @@ public interface Size extends Metadata { * of a column value, in bytes. Each value or the entire list may be null if * the metadata is not available */ - @Nullable List averageColumnSizes(); + List<@Nullable Double> averageColumnSizes(); /** Handler API. */ interface Handler extends MetadataHandler { @Nullable Double averageRowSize(RelNode r, RelMetadataQuery mq); - @Nullable List averageColumnSizes(RelNode r, RelMetadataQuery mq); + @Nullable List<@Nullable Double> averageColumnSizes(RelNode r, RelMetadataQuery mq); } } diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdAllPredicates.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdAllPredicates.java index beac32d88232..6b74ba4c0484 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdAllPredicates.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdAllPredicates.java @@ -259,7 +259,8 @@ public MetadataDef getDef() { /** * Extract predicates for an TableModify. */ - public @Nullable RelOptPredicateList getAllPredicates(TableModify tableModify, RelMetadataQuery mq) { + public @Nullable RelOptPredicateList getAllPredicates(TableModify tableModify, + RelMetadataQuery mq) { return mq.getAllPredicates(tableModify.getInput()); } diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java index a42ed2ab0930..13bad263ce32 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java @@ -41,6 +41,8 @@ import org.apache.calcite.util.NumberUtil; import org.apache.calcite.util.Util; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * RelMdRowCount supplies a default implementation of * {@link RelMetadataQuery#getRowCount} for the standard logical algebra. @@ -63,11 +65,11 @@ public MetadataDef getDef() { * * @see org.apache.calcite.rel.metadata.RelMetadataQuery#getRowCount(RelNode) */ - public Double getRowCount(RelNode rel, RelMetadataQuery mq) { + public @Nullable Double getRowCount(RelNode rel, RelMetadataQuery mq) { return rel.estimateRowCount(mq); } - public Double getRowCount(RelSubset subset, RelMetadataQuery mq) { + public @Nullable Double getRowCount(RelSubset subset, RelMetadataQuery mq) { if (!Bug.CALCITE_1048_FIXED) { return mq.getRowCount(Util.first(subset.getBest(), subset.getOriginal())); } @@ -84,7 +86,7 @@ public Double getRowCount(RelSubset subset, RelMetadataQuery mq) { return Util.first(v, 1e6d); // if set is empty, estimate large } - public Double getRowCount(Union rel, RelMetadataQuery mq) { + public @Nullable Double getRowCount(Union rel, RelMetadataQuery mq) { double rowCount = 0.0; for (RelNode input : rel.getInputs()) { Double partialRowCount = mq.getRowCount(input); @@ -99,7 +101,7 @@ public Double getRowCount(Union rel, RelMetadataQuery mq) { return rowCount; } - public Double getRowCount(Intersect rel, RelMetadataQuery mq) { + public @Nullable Double getRowCount(Intersect rel, RelMetadataQuery mq) { Double rowCount = null; for (RelNode input : rel.getInputs()) { Double partialRowCount = mq.getRowCount(input); @@ -115,7 +117,7 @@ public Double getRowCount(Intersect rel, RelMetadataQuery mq) { } } - public Double getRowCount(Minus rel, RelMetadataQuery mq) { + public @Nullable Double getRowCount(Minus rel, RelMetadataQuery mq) { Double rowCount = null; for (RelNode input : rel.getInputs()) { Double partialRowCount = mq.getRowCount(input); @@ -136,11 +138,11 @@ public Double getRowCount(Calc rel, RelMetadataQuery mq) { return RelMdUtil.estimateFilteredRows(rel.getInput(), rel.getProgram(), mq); } - public Double getRowCount(Project rel, RelMetadataQuery mq) { + public @Nullable Double getRowCount(Project rel, RelMetadataQuery mq) { return mq.getRowCount(rel.getInput()); } - public Double getRowCount(Sort rel, RelMetadataQuery mq) { + public @Nullable Double getRowCount(Sort rel, RelMetadataQuery mq) { Double rowCount = mq.getRowCount(rel.getInput()); if (rowCount == null) { return null; @@ -163,7 +165,7 @@ public Double getRowCount(Sort rel, RelMetadataQuery mq) { return rowCount; } - public Double getRowCount(EnumerableLimit rel, RelMetadataQuery mq) { + public @Nullable Double getRowCount(EnumerableLimit rel, RelMetadataQuery mq) { Double rowCount = mq.getRowCount(rel.getInput()); if (rowCount == null) { return null; @@ -187,11 +189,11 @@ public Double getRowCount(EnumerableLimit rel, RelMetadataQuery mq) { } // Covers Converter, Interpreter - public Double getRowCount(SingleRel rel, RelMetadataQuery mq) { + public @Nullable Double getRowCount(SingleRel rel, RelMetadataQuery mq) { return mq.getRowCount(rel.getInput()); } - public Double getRowCount(Join rel, RelMetadataQuery mq) { + public @Nullable Double getRowCount(Join rel, RelMetadataQuery mq) { return RelMdUtil.getJoinRowCount(mq, rel, rel.getCondition()); } @@ -219,11 +221,11 @@ public Double getRowCount(Values rel, RelMetadataQuery mq) { return rel.estimateRowCount(mq); } - public Double getRowCount(Exchange rel, RelMetadataQuery mq) { + public @Nullable Double getRowCount(Exchange rel, RelMetadataQuery mq) { return mq.getRowCount(rel.getInput()); } - public Double getRowCount(TableModify rel, RelMetadataQuery mq) { + public @Nullable Double getRowCount(TableModify rel, RelMetadataQuery mq) { return mq.getRowCount(rel.getInput()); } } diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java index 458df6b3448e..0f91c9733ef7 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java @@ -45,6 +45,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.List; @@ -108,27 +110,27 @@ public Double averageRowSize(RelNode rel, RelMetadataQuery mq) { * * @see org.apache.calcite.rel.metadata.RelMetadataQuery#getAverageColumnSizes */ - public List averageColumnSizes(RelNode rel, RelMetadataQuery mq) { + public @Nullable List<@Nullable Double> averageColumnSizes(RelNode rel, RelMetadataQuery mq) { return null; // absolutely no idea } - public List averageColumnSizes(Filter rel, RelMetadataQuery mq) { + public @Nullable List<@Nullable Double> averageColumnSizes(Filter rel, RelMetadataQuery mq) { return mq.getAverageColumnSizes(rel.getInput()); } - public List averageColumnSizes(Sort rel, RelMetadataQuery mq) { + public @Nullable List<@Nullable Double> averageColumnSizes(Sort rel, RelMetadataQuery mq) { return mq.getAverageColumnSizes(rel.getInput()); } - public List averageColumnSizes(TableModify rel, RelMetadataQuery mq) { + public @Nullable List<@Nullable Double> averageColumnSizes(TableModify rel, RelMetadataQuery mq) { return mq.getAverageColumnSizes(rel.getInput()); } - public List averageColumnSizes(Exchange rel, RelMetadataQuery mq) { + public @Nullable List<@Nullable Double> averageColumnSizes(Exchange rel, RelMetadataQuery mq) { return mq.getAverageColumnSizes(rel.getInput()); } - public List averageColumnSizes(Project rel, RelMetadataQuery mq) { + public @Nullable List<@Nullable Double> averageColumnSizes(Project rel, RelMetadataQuery mq) { final List inputColumnSizes = mq.getAverageColumnSizesNotNull(rel.getInput()); final ImmutableNullableList.Builder sizes = @@ -139,7 +141,7 @@ public List averageColumnSizes(Project rel, RelMetadataQuery mq) { return sizes.build(); } - public List averageColumnSizes(Calc rel, RelMetadataQuery mq) { + public @Nullable List<@Nullable Double> averageColumnSizes(Calc rel, RelMetadataQuery mq) { final List inputColumnSizes = mq.getAverageColumnSizesNotNull(rel.getInput()); final ImmutableNullableList.Builder sizes = @@ -149,7 +151,7 @@ public List averageColumnSizes(Calc rel, RelMetadataQuery mq) { return sizes.build(); } - public List averageColumnSizes(Values rel, RelMetadataQuery mq) { + public @Nullable List<@Nullable Double> averageColumnSizes(Values rel, RelMetadataQuery mq) { final List fields = rel.getRowType().getFieldList(); final ImmutableList.Builder list = ImmutableList.builder(); for (int i = 0; i < fields.size(); i++) { @@ -170,7 +172,7 @@ public List averageColumnSizes(Values rel, RelMetadataQuery mq) { return list.build(); } - public List averageColumnSizes(TableScan rel, RelMetadataQuery mq) { + public List<@Nullable Double> averageColumnSizes(TableScan rel, RelMetadataQuery mq) { final List fields = rel.getRowType().getFieldList(); final ImmutableList.Builder list = ImmutableList.builder(); for (RelDataTypeField field : fields) { @@ -179,7 +181,7 @@ public List averageColumnSizes(TableScan rel, RelMetadataQuery mq) { return list.build(); } - public List averageColumnSizes(Aggregate rel, RelMetadataQuery mq) { + public List<@Nullable Double> averageColumnSizes(Aggregate rel, RelMetadataQuery mq) { final List inputColumnSizes = mq.getAverageColumnSizesNotNull(rel.getInput()); final ImmutableList.Builder list = ImmutableList.builder(); @@ -192,7 +194,7 @@ public List averageColumnSizes(Aggregate rel, RelMetadataQuery mq) { return list.build(); } - public List averageColumnSizes(Join rel, RelMetadataQuery mq) { + public List<@Nullable Double> averageColumnSizes(Join rel, RelMetadataQuery mq) { return averageJoinColumnSizes(rel, mq); } @@ -220,15 +222,15 @@ private List averageJoinColumnSizes(Join rel, RelMetadataQuery mq) { return ImmutableNullableList.copyOf(sizes); } - public List averageColumnSizes(Intersect rel, RelMetadataQuery mq) { + public @Nullable List<@Nullable Double> averageColumnSizes(Intersect rel, RelMetadataQuery mq) { return mq.getAverageColumnSizes(rel.getInput(0)); } - public List averageColumnSizes(Minus rel, RelMetadataQuery mq) { + public @Nullable List<@Nullable Double> averageColumnSizes(Minus rel, RelMetadataQuery mq) { return mq.getAverageColumnSizes(rel.getInput(0)); } - public List averageColumnSizes(Union rel, RelMetadataQuery mq) { + public List<@Nullable Double> averageColumnSizes(Union rel, RelMetadataQuery mq) { final int fieldCount = rel.getRowType().getFieldCount(); List> inputColumnSizeList = new ArrayList<>(); for (RelNode input : rel.getInputs()) { diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java index 34b659da2029..6ae53c6337b6 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java @@ -40,6 +40,8 @@ import java.util.Objects; import java.util.Set; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * RelMetadataQuery provides a strongly-typed facade on top of * {@link RelMetadataProvider} for the set of relational expression metadata @@ -108,7 +110,7 @@ public class RelMetadataQuery extends RelMetadataQueryBase { * from {@link #THREAD_PROVIDERS} and {@link #EMPTY} as a prototype. */ protected RelMetadataQuery() { - this(THREAD_PROVIDERS.get(), EMPTY); + this(castNonNull(THREAD_PROVIDERS.get()), EMPTY); } /** Creates and initializes the instance that will serve as a prototype for @@ -629,7 +631,7 @@ public RelDistribution distribution(RelNode rel) { * value, in bytes. Each value or the entire list may be null if the * metadata is not available */ - public @Nullable List getAverageColumnSizes(RelNode rel) { + public @Nullable List<@Nullable Double> getAverageColumnSizes(RelNode rel) { for (;;) { try { return sizeHandler.averageColumnSizes(rel, this); @@ -641,8 +643,8 @@ public RelDistribution distribution(RelNode rel) { /** As {@link #getAverageColumnSizes(org.apache.calcite.rel.RelNode)} but * never returns a null list, only ever a list of nulls. */ - public @Nullable List getAverageColumnSizesNotNull(RelNode rel) { - final List averageColumnSizes = getAverageColumnSizes(rel); + public List<@Nullable Double> getAverageColumnSizesNotNull(RelNode rel) { + final @Nullable List<@Nullable Double> averageColumnSizes = getAverageColumnSizes(rel); return averageColumnSizes == null ? Collections.nCopies(rel.getRowType().getFieldCount(), null) : averageColumnSizes; diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQueryBase.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQueryBase.java index 0de898c33874..b987773cd869 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQueryBase.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQueryBase.java @@ -21,11 +21,15 @@ import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.reflect.Proxy; import java.util.List; import java.util.Map; import java.util.function.Supplier; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; + /** * Base class for the RelMetadataQuery that uses the metadata handler class * generated by the Janino. @@ -64,16 +68,16 @@ public class RelMetadataQueryBase { /** Set of active metadata queries, and cache of previous results. */ public final Table map = HashBasedTable.create(); - public final JaninoRelMetadataProvider metadataProvider; + public final @Nullable JaninoRelMetadataProvider metadataProvider; //~ Static fields/initializers --------------------------------------------- - public static final ThreadLocal THREAD_PROVIDERS = + public static final ThreadLocal<@Nullable JaninoRelMetadataProvider> THREAD_PROVIDERS = new ThreadLocal<>(); //~ Constructors ----------------------------------------------------------- - protected RelMetadataQueryBase(JaninoRelMetadataProvider metadataProvider) { + protected RelMetadataQueryBase(@Nullable JaninoRelMetadataProvider metadataProvider) { this.metadataProvider = metadataProvider; } @@ -81,7 +85,7 @@ protected static H initialHandler(Class handlerClass) { return handlerClass.cast( Proxy.newProxyInstance(RelMetadataQuery.class.getClassLoader(), new Class[] {handlerClass}, (proxy, method, args) -> { - final RelNode r = (RelNode) args[0]; + final RelNode r = assertNonNull((RelNode) args[0], "(RelNode) args[0]"); throw new JaninoRelMetadataProvider.NoHandler(r.getClass()); })); } @@ -92,6 +96,7 @@ protected static H initialHandler(Class handlerClass) { * {@code class_} if it is not already present. */ protected > H revise(Class class_, MetadataDef def) { + assertNonNull(metadataProvider, "metadataProvider"); return metadataProvider.revise(class_, def); } 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 1c61f8f6a2bb..f78eeed3d724 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 @@ -92,6 +92,8 @@ import com.google.common.collect.Lists; import com.google.common.collect.Ordering; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; @@ -667,7 +669,7 @@ dual, createAlwaysFalseCondition(), null, return result(query, clauses, e, null); } - private SqlIdentifier getDual() { + private @Nullable SqlIdentifier getDual() { final List names = dialect.getSingleRowTableName(); if (names == null) { return 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 1499c945ec54..81a6cdc028b3 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 @@ -16,7 +16,6 @@ */ package org.apache.calcite.rel.rel2sql; -import org.apache.calcite.linq4j.Nullness; import org.apache.calcite.linq4j.Ord; import org.apache.calcite.linq4j.tree.Expressions; import org.apache.calcite.rel.RelFieldCollation; @@ -92,6 +91,9 @@ import com.google.common.collect.Lists; import com.google.common.collect.Range; +import org.checkerframework.checker.initialization.qual.UnknownInitialization; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.math.BigDecimal; import java.util.AbstractList; import java.util.ArrayDeque; @@ -112,9 +114,9 @@ import java.util.function.Function; import java.util.function.IntFunction; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import static org.apache.calcite.linq4j.Nullness.assertNonNull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; /** * State for generating a SQL statement. @@ -266,6 +268,8 @@ public Result setOpToSql(SqlSetOperator operator, RelNode rel) { node = operator.createCall(POS, node, result.asSelect()); } } + assert node != null : "set op must have at least one input, operator = " + operator + + ", rel = " + rel; final List clauses = Expressions.list(Clause.SET_OP); return result(node, clauses, rel, null); @@ -280,7 +284,7 @@ public Result setOpToSql(SqlSetOperator operator, RelNode rel) { * @param leftFieldCount Number of fields on left result * @return SqlNode that represents the condition */ - public static @Nullable SqlNode convertConditionToSqlNode(RexNode node, + public static SqlNode convertConditionToSqlNode(RexNode node, Context leftContext, Context rightContext, int leftFieldCount, @@ -492,7 +496,7 @@ public Result result(SqlNode node, Collection clauses, *

Call this method rather than creating a {@code Result} directly, * because sub-classes may override. */ protected Result result(SqlNode node, Collection clauses, - @Nullable String neededAlias, RelDataType neededType, + @Nullable String neededAlias, @Nullable RelDataType neededType, Map aliases) { return new Result(node, clauses, neededAlias, neededType, aliases); } @@ -784,7 +788,7 @@ public SqlNode toSql(@Nullable RexProgram program, RexNode rex) { case SEARCH: final RexCall search = (RexCall) rex; literal = (RexLiteral) search.operands.get(1); - final Sarg sarg = literal.getValueAs(Sarg.class); + final Sarg sarg = castNonNull(literal.getValueAs(Sarg.class)); //noinspection unchecked return toSql(program, search.operands.get(0), literal.getType(), sarg); @@ -839,7 +843,7 @@ public SqlNode toSql(@Nullable RexProgram program, RexNode rex) { assert nodeList.size() == 1; return nodeList.get(0); } else { - nodeList.add(dialect.getCastSpec(call.getType())); + nodeList.add(castNonNull(dialect.getCastSpec(call.getType()))); } } return SqlUtil.createCall(op, POS, nodeList); @@ -849,7 +853,7 @@ public SqlNode toSql(@Nullable RexProgram program, RexNode rex) { /** Converts a Sarg to SQL, generating "operand IN (c1, c2, ...)" if the * ranges are all points. */ @SuppressWarnings("UnstableApiUsage") - private > SqlNode toSql(RexProgram program, + private > SqlNode toSql(@Nullable RexProgram program, RexNode operand, RelDataType type, Sarg sarg) { final List orList = new ArrayList<>(); final SqlNode operandSql = toSql(program, operand); @@ -1263,7 +1267,7 @@ private SqlNode op(SqlOperator op, C value) { /** Converts a {@link RexLiteral} in the context of a {@link RexProgram} * to a {@link SqlNode}. */ - public static SqlNode toSql(RexProgram program, RexLiteral literal) { + public static SqlNode toSql(@Nullable RexProgram program, RexLiteral literal) { switch (literal.getTypeName()) { case SYMBOL: final Enum symbol = (Enum) literal.getValue(); @@ -1271,7 +1275,7 @@ public static SqlNode toSql(RexProgram program, RexLiteral literal) { case ROW: //noinspection unchecked - final List list = literal.getValueAs(List.class); + final List list = castNonNull(literal.getValueAs(List.class)); return SqlStdOperatorTable.ROW.createCall(POS, list.stream().map(e -> toSql(program, e)) .collect(Util.toImmutableList())); @@ -1295,7 +1299,7 @@ public static SqlNode toSql(RexLiteral literal) { case ROW: //noinspection unchecked - final List list = literal.getValueAs(List.class); + final List list = castNonNull(literal.getValueAs(List.class)); return SqlStdOperatorTable.ROW.createCall(POS, list.stream().map(e -> toSql(e)) .collect(Util.toImmutableList())); @@ -1307,32 +1311,32 @@ public static SqlNode toSql(RexLiteral literal) { } switch (literal.getTypeName().getFamily()) { case CHARACTER: - return SqlLiteral.createCharString((String) literal.getValue2(), POS); + return SqlLiteral.createCharString((String) castNonNull(literal.getValue2()), POS); case NUMERIC: case EXACT_NUMERIC: return SqlLiteral.createExactNumeric( - literal.getValueAs(BigDecimal.class).toPlainString(), POS); + castNonNull(literal.getValueAs(BigDecimal.class)).toPlainString(), POS); case APPROXIMATE_NUMERIC: return SqlLiteral.createApproxNumeric( - literal.getValueAs(BigDecimal.class).toPlainString(), POS); + castNonNull(literal.getValueAs(BigDecimal.class)).toPlainString(), POS); case BOOLEAN: - return SqlLiteral.createBoolean(literal.getValueAs(Boolean.class), + return SqlLiteral.createBoolean(castNonNull(literal.getValueAs(Boolean.class)), POS); case INTERVAL_YEAR_MONTH: case INTERVAL_DAY_TIME: - final boolean negative = literal.getValueAs(Boolean.class); + final boolean negative = castNonNull(literal.getValueAs(Boolean.class)); return SqlLiteral.createInterval(negative ? -1 : 1, - literal.getValueAs(String.class), - literal.getType().getIntervalQualifier(), POS); + castNonNull(literal.getValueAs(String.class)), + castNonNull(literal.getType().getIntervalQualifier()), POS); case DATE: - return SqlLiteral.createDate(literal.getValueAs(DateString.class), + return SqlLiteral.createDate(castNonNull(literal.getValueAs(DateString.class)), POS); case TIME: - return SqlLiteral.createTime(literal.getValueAs(TimeString.class), + return SqlLiteral.createTime(castNonNull(literal.getValueAs(TimeString.class)), literal.getType().getPrecision(), POS); case TIMESTAMP: return SqlLiteral.createTimestamp( - literal.getValueAs(TimestampString.class), + castNonNull(literal.getValueAs(TimestampString.class)), literal.getType().getPrecision(), POS); case ANY: case NULL: @@ -1375,7 +1379,9 @@ protected abstract class BaseContext extends Context { } @Override protected Context getAliasContext(RexCorrelVariable variable) { - return correlTableMap.get(variable.id); + return assertNonNull( + correlTableMap.get(variable.id), + () -> "variable " + variable.id + " is not found"); } @Override public SqlImplementor implementor() { @@ -1416,11 +1422,11 @@ protected MatchRecognizeContext(SqlDialect dialect, super(dialect, aliases, false); } - @Override public SqlNode toSql(RexProgram program, RexNode rex) { + @Override public SqlNode toSql(@Nullable RexProgram program, RexNode rex) { if (rex.getKind() == SqlKind.LITERAL) { final RexLiteral literal = (RexLiteral) rex; if (literal.getTypeName().getFamily() == SqlTypeFamily.CHARACTER) { - return new SqlIdentifier(RexLiteral.stringValue(literal), POS); + return new SqlIdentifier(castNonNull(RexLiteral.stringValue(literal)), POS); } } return super.toSql(program, rex); @@ -1499,7 +1505,7 @@ class TableFunctionScanContext extends BaseContext { public class Result { final SqlNode node; final @Nullable String neededAlias; - private final RelDataType neededType; + private final @Nullable RelDataType neededType; private final Map aliases; final List clauses; private final boolean anon; @@ -1513,13 +1519,13 @@ public class Result { private final boolean needNew; public Result(SqlNode node, Collection clauses, @Nullable String neededAlias, - RelDataType neededType, Map aliases) { + @Nullable RelDataType neededType, Map aliases) { this(node, clauses, neededAlias, neededType, aliases, false, false, ImmutableSet.of(), null); } private Result(SqlNode node, Collection clauses, @Nullable String neededAlias, - RelDataType neededType, Map aliases, boolean anon, + @Nullable RelDataType neededType, Map aliases, boolean anon, boolean ignoreClauses, Set expectedClauses, @Nullable RelNode expectedRel) { this.node = node; @@ -1660,11 +1666,13 @@ private Builder builder(RelNode rel, Set clauses) { } } return new Builder(rel, clauseList, select, newContext, isAnon(), - needNew && !aliases.containsKey(neededAlias) ? newAliases : aliases); + needNew && !aliases.containsKey(castNonNull(neededAlias)) ? newAliases : aliases); } /** Returns whether a new sub-query is required. */ - private boolean needNewSubQuery(RelNode rel, List clauses, + private boolean needNewSubQuery( + @UnknownInitialization Result this, + RelNode rel, List clauses, Set expectedClauses) { if (clauses.isEmpty()) { return false; @@ -1712,7 +1720,9 @@ private boolean needNewSubQuery(RelNode rel, List clauses, return false; } - private boolean hasNestedAggregations(Aggregate rel) { + private boolean hasNestedAggregations( + @UnknownInitialization Result this, + Aggregate rel) { if (node instanceof SqlSelect) { final SqlNodeList selectList = ((SqlSelect) node).getSelectList(); if (selectList != null) { @@ -1753,6 +1763,8 @@ public SqlNode asFrom() { // If we already have an AS node, we need to replace the alias // This is especially relevant for the VALUES clause rendering SqlCall sqlCall = (SqlCall) node; + @SuppressWarnings({"assignment.type.incompatible", + "toArray.nullable.elements.not.newarray"}) SqlNode[] operands = sqlCall.getOperandList().toArray(SqlNode.EMPTY_ARRAY); operands[1] = new SqlIdentifier(neededAlias, POS); return SqlStdOperatorTable.AS.createCall(POS, operands); @@ -1873,7 +1885,7 @@ public Result resetAlias() { return this; } else { return new Result(node, clauses, neededAlias, neededType, - ImmutableMap.of(neededAlias, neededType), anon, ignoreClauses, + ImmutableMap.of(neededAlias, castNonNull(neededType)), anon, ignoreClauses, expectedClauses, expectedRel); } } 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 ba2a77776536..c64f09eaa4b4 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 @@ -51,6 +51,8 @@ import com.google.common.collect.RangeSet; import com.google.common.collect.TreeRangeSet; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.math.BigDecimal; import java.util.ArrayDeque; import java.util.ArrayList; @@ -229,7 +231,7 @@ private static class ExtractFinder extends RexVisitorImpl EnumSet.noneOf(TimeUnitRange.class); private final Set opKinds = EnumSet.noneOf(SqlKind.class); - private static final ThreadLocal THREAD_INSTANCES = + private static final ThreadLocal<@Nullable ExtractFinder> THREAD_INSTANCES = ThreadLocal.withInitial(ExtractFinder::new); private ExtractFinder() { diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java b/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java index dca2fe2028a3..d78ad3779c5a 100644 --- a/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java +++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataType.java @@ -144,6 +144,7 @@ public interface RelDataType { * * @return charset of type */ + @Pure @Nullable Charset getCharset(); /** @@ -152,6 +153,7 @@ public interface RelDataType { * * @return collation of type */ + @Pure @Nullable SqlCollation getCollation(); /** @@ -160,6 +162,7 @@ public interface RelDataType { * * @return interval qualifier */ + @Pure @Nullable SqlIntervalQualifier getIntervalQualifier(); /** @@ -203,6 +206,7 @@ public interface RelDataType { * * @return SqlIdentifier, or null if this is not an SQL type */ + @Pure @Nullable SqlIdentifier getSqlIdentifier(); /** diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeImpl.java b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeImpl.java index 6bd96aacd039..f42030d96354 100644 --- a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeImpl.java +++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeImpl.java @@ -28,7 +28,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; -import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.Nullable; diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java index 430496e36cec..33b2237c0205 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java +++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java @@ -60,10 +60,12 @@ import com.google.common.collect.TreeRangeSet; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.PolyNull; import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -73,6 +75,8 @@ import java.util.Objects; import javax.annotation.Nonnull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Factory for row expressions. * @@ -625,7 +629,7 @@ protected static TimeUnit baseUnit(SqlTypeName unit) { } } - boolean canRemoveCastFromLiteral(RelDataType toType, Comparable value, + boolean canRemoveCastFromLiteral(RelDataType toType, @Nullable Comparable value, SqlTypeName fromTypeName) { final SqlTypeName sqlType = toType.getSqlTypeName(); if (!RexLiteral.valueMatchesType(value, sqlType, false)) { @@ -936,15 +940,16 @@ protected RexLiteral makeLiteral( NlsString nlsString = (NlsString) o; if (nlsString.getCollation() == null || nlsString.getCharset() == null - || !nlsString.getCharset().equals(type.getCharset()) - || !nlsString.getCollation().equals(type.getCollation())) { + || !Objects.equals(nlsString.getCharset(), type.getCharset()) + || !Objects.equals(nlsString.getCollation(), type.getCollation())) { assert type.getSqlTypeName() == SqlTypeName.CHAR || type.getSqlTypeName() == SqlTypeName.VARCHAR; - assert type.getCharset().name() != null; - assert type.getCollation() != null; + Charset charset = type.getCharset(); + assert charset != null : "type.getCharset() must not be null"; + assert type.getCollation() != null : "type.getCollation() must not be null"; o = new NlsString( nlsString.getValue(), - type.getCharset().name(), + charset.name(), type.getCollation()); } break; @@ -1364,7 +1369,7 @@ && areAssignable(arg, Arrays.asList(lower, upper))) { /** Converts a list of expressions to a search argument, or returns null if * not possible. */ @SuppressWarnings("UnstableApiUsage") - private static > Sarg toSarg(Class clazz, + private static > @Nullable Sarg toSarg(Class clazz, List ranges, boolean containsNull) { if (ranges.isEmpty()) { // Cannot convert an empty list to a Sarg (by this interface, at least) @@ -1382,7 +1387,7 @@ private static > Sarg toSarg(Class clazz, return Sarg.of(containsNull, rangeSet); } - private static > C toComparable(Class clazz, + private static > @Nullable C toComparable(Class clazz, RexNode point) { switch (point.getKind()) { case LITERAL: @@ -1510,7 +1515,7 @@ public RexNode makeLiteral(Object value, RelDataType type, * to CHAR(3) 'foo' * @return Simple literal, or cast simple literal */ - public RexNode makeLiteral(Object value, RelDataType type, + public RexNode makeLiteral(@Nullable Object value, RelDataType type, boolean allowCast, boolean trim) { if (value == null) { return makeCast(type, constantNull); @@ -1586,7 +1591,7 @@ public RexNode makeLiteral(Object value, RelDataType type, case INTERVAL_MINUTE_SECOND: case INTERVAL_SECOND: return makeIntervalLiteral((BigDecimal) value, - type.getIntervalQualifier()); + castNonNull(type.getIntervalQualifier())); case SYMBOL: return makeFlag((Enum) value); case MAP: @@ -1651,9 +1656,9 @@ public RexNode makeLiteral(Object value, RelDataType type, /** Converts the type of a value to comply with * {@link org.apache.calcite.rex.RexLiteral#valueMatchesType}. */ - private static Object clean(Object o, RelDataType type) { + private static @PolyNull Object clean(@PolyNull Object o, RelDataType type) { if (o == null) { - return null; + return o; } switch (type.getSqlTypeName()) { case TINYINT: @@ -1701,6 +1706,7 @@ private static Object clean(Object o, RelDataType type) { if (o instanceof NlsString) { return o; } + assert type.getCharset() != null : type + ".getCharset() must not be null"; return new NlsString((String) o, type.getCharset().name(), type.getCollation()); case TIME: @@ -1753,7 +1759,7 @@ private static Object clean(Object o, RelDataType type) { } } - private RelDataType guessType(Object value) { + private RelDataType guessType(@Nullable Object value) { if (value == null) { return typeFactory.createSqlType(SqlTypeName.NULL); } diff --git a/core/src/main/java/org/apache/calcite/rex/RexCorrelVariable.java b/core/src/main/java/org/apache/calcite/rex/RexCorrelVariable.java index fa900cfebbc6..b09a23b865db 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexCorrelVariable.java +++ b/core/src/main/java/org/apache/calcite/rex/RexCorrelVariable.java @@ -60,7 +60,7 @@ public R accept(RexBiVisitor visitor, P arg) { @Override public boolean equals(@Nullable Object obj) { return this == obj || obj instanceof RexCorrelVariable - && digest.equals(((RexCorrelVariable) obj).digest) + && Objects.equals(digest, ((RexCorrelVariable) obj).digest) && type.equals(((RexCorrelVariable) obj).type) && id.equals(((RexCorrelVariable) obj).id); } diff --git a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java index 1fc8b2f58756..746e129ac1d4 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java +++ b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java @@ -46,7 +46,10 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.initialization.qual.UnknownInitialization; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.PolyNull; +import org.checkerframework.checker.nullness.qual.RequiresNonNull; import java.io.PrintWriter; import java.math.BigDecimal; @@ -60,6 +63,9 @@ import java.util.Objects; import java.util.TimeZone; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Constant value in a row-expression. * @@ -259,7 +265,10 @@ public class RexLiteral extends RexNode { * @param includeType whether the digest should include type or not * @return digest */ - public final String computeDigest(RexDigestIncludeType includeType) { + @RequiresNonNull({"typeName", "type"}) + public final String computeDigest( + @UnknownInitialization RexLiteral this, + RexDigestIncludeType includeType) { if (includeType == RexDigestIncludeType.OPTIONAL) { if (digest != null) { // digest is initialized with OPTIONAL, so cached value matches for @@ -284,7 +293,10 @@ public final String computeDigest(RexDigestIncludeType includeType) { * @see RexCall#computeDigest(boolean) * @return true if {@link RexDigestIncludeType#OPTIONAL} digest would include data type */ - RexDigestIncludeType digestIncludesType() { + @RequiresNonNull("type") + RexDigestIncludeType digestIncludesType( + @UnknownInitialization RexLiteral this + ) { return shouldIncludeType(value, type); } @@ -435,7 +447,8 @@ private static String toJavaString( * @param type type of the literal * @return NO_TYPE when type can be omitted, ALWAYS otherwise */ - private static RexDigestIncludeType shouldIncludeType(Comparable value, RelDataType type) { + private static RexDigestIncludeType shouldIncludeType(@Nullable Comparable value, + RelDataType type) { if (type.isNullable()) { // This means "null literal", so we require a type for it // There might be exceptions like AND(null, true) which are handled by RexCall#computeDigest @@ -456,10 +469,11 @@ private static RexDigestIncludeType shouldIncludeType(Comparable value, RelDataT // Ignore type information for 'Bar':CHAR(3) if (( - (nlsString.getCharset() != null && type.getCharset().equals(nlsString.getCharset())) + (nlsString.getCharset() != null + && Objects.equals(type.getCharset(), nlsString.getCharset())) || (nlsString.getCharset() == null - && SqlCollation.IMPLICIT.getCharset().equals(type.getCharset()))) - && nlsString.getCollation().equals(type.getCollation()) + && Objects.equals(SqlCollation.IMPLICIT.getCharset(), type.getCharset()))) + && Objects.equals(nlsString.getCollation(), type.getCollation()) && ((NlsString) value).getValue().length() == type.getPrecision()) { includeType = RexDigestIncludeType.NO_TYPE; } else { @@ -605,7 +619,7 @@ private static void appendAsJava(@Nullable Comparable value, StringBuilder sb, RexDigestIncludeType includeType) { switch (typeName) { case CHAR: - NlsString nlsString = (NlsString) value; + NlsString nlsString = (NlsString) castNonNull(value); if (java) { Util.printJavaString( sb, @@ -691,13 +705,15 @@ private static void appendAsJava(@Nullable Comparable value, StringBuilder sb, break; case MULTISET: case ROW: - final List list = (List) value; + assert value instanceof List : "value must implement List: " + value; + @SuppressWarnings("unchecked") final List list = + (List) castNonNull(value); Util.asStringBuilder(sb, sb2 -> Util.printList(sb, list.size(), (sb3, i) -> sb3.append(list.get(i).computeDigest(includeType)))); break; case GEOMETRY: - final String wkt = GeoFunctions.ST_AsWKT((Geometries.Geom) value); + final String wkt = GeoFunctions.ST_AsWKT((Geometries.Geom) castNonNull(value)); sb.append(wkt); break; default: @@ -719,6 +735,7 @@ private static RexLiteral toLiteral(RelDataType type, Comparable value) { final SqlTypeName typeName = strictTypeName(type); switch (typeName) { case ROW: + assert value instanceof List : "value must implement List: " + value; final List> fieldValues = (List) value; final List fields = type.getFieldList(); final List fieldLiterals = @@ -728,11 +745,12 @@ private static RexLiteral toLiteral(RelDataType type, Comparable value) { return new RexLiteral((Comparable) fieldLiterals, type, typeName); case MULTISET: + assert value instanceof List : "value must implement List: " + value; final List> elementValues = (List) value; final List elementLiterals = FlatLists.of( Functions.generate(elementValues.size(), i -> - toLiteral(type.getComponentType(), elementValues.get(i)))); + toLiteral(castNonNull(type.getComponentType()), elementValues.get(i)))); return new RexLiteral((Comparable) elementLiterals, type, typeName); default: @@ -754,17 +772,17 @@ private static RexLiteral toLiteral(RelDataType type, Comparable value) { * by the Jdbc call to return a column as a string * @return a typed RexLiteral, or null */ - public static RexLiteral fromJdbcString( + public static @PolyNull RexLiteral fromJdbcString( RelDataType type, SqlTypeName typeName, - String literal) { + @PolyNull String literal) { if (literal == null) { return null; } switch (typeName) { case CHAR: - Charset charset = type.getCharset(); + Charset charset = assertNonNull(type.getCharset(), () -> "charset for " + type); SqlCollation collation = type.getCollation(); NlsString str = new NlsString( @@ -797,7 +815,7 @@ public static RexLiteral fromJdbcString( long millis = SqlParserUtil.intervalToMillis( literal, - type.getIntervalQualifier()); + castNonNull(type.getIntervalQualifier())); return new RexLiteral(BigDecimal.valueOf(millis), type, typeName); case INTERVAL_YEAR: case INTERVAL_YEAR_MONTH: @@ -805,7 +823,7 @@ public static RexLiteral fromJdbcString( long months = SqlParserUtil.intervalToMonths( literal, - type.getIntervalQualifier()); + castNonNull(type.getIntervalQualifier())); return new RexLiteral(BigDecimal.valueOf(months), type, typeName); case DATE: case TIME: @@ -1101,10 +1119,10 @@ public boolean isNull() { } else if (clazz == Long.class) { return clazz.cast(((BigDecimal) value).longValue()); } else if (clazz == String.class) { - return clazz.cast(intervalString(getValueAs(BigDecimal.class).abs())); + return clazz.cast(intervalString(castNonNull(getValueAs(BigDecimal.class)).abs())); } else if (clazz == Boolean.class) { // return whether negative - return clazz.cast(getValueAs(BigDecimal.class).signum() < 0); + return clazz.cast(castNonNull(getValueAs(BigDecimal.class)).signum() < 0); } break; } @@ -1113,7 +1131,7 @@ public boolean isNull() { } public static boolean booleanValue(RexNode node) { - return (Boolean) ((RexLiteral) node).value; + return (Boolean) castNonNull(((RexLiteral) node).value); } public boolean isAlwaysTrue() { @@ -1148,7 +1166,7 @@ public int hashCode() { } public static int intValue(RexNode node) { - final Comparable value = findValue(node); + final Comparable value = castNonNull(findValue(node)); return ((Number) value).intValue(); } @@ -1170,7 +1188,7 @@ public static int intValue(RexNode node) { if (operator == SqlStdOperatorTable.UNARY_MINUS) { final BigDecimal value = (BigDecimal) findValue(call.getOperands().get(0)); - return value.negate(); + return assertNonNull(value, () -> "can't negate null in " + node).negate(); } } throw new AssertionError("not a literal: " + node); diff --git a/core/src/main/java/org/apache/calcite/rex/RexNode.java b/core/src/main/java/org/apache/calcite/rex/RexNode.java index 38a32fbfbdd6..a02e629a0709 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexNode.java +++ b/core/src/main/java/org/apache/calcite/rex/RexNode.java @@ -19,6 +19,7 @@ import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.sql.SqlKind; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Collection; @@ -44,7 +45,7 @@ public abstract class RexNode { //~ Instance fields -------------------------------------------------------- // Effectively final. Set in each sub-class constructor, and never re-set. - protected @Nullable String digest; + protected @MonotonicNonNull String digest; //~ Methods ---------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rex/RexProgram.java b/core/src/main/java/org/apache/calcite/rex/RexProgram.java index 7aac0319386b..8cb9d8bb7e81 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexProgram.java +++ b/core/src/main/java/org/apache/calcite/rex/RexProgram.java @@ -41,6 +41,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Ordering; +import org.checkerframework.checker.initialization.qual.UnknownInitialization; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; import java.io.PrintWriter; @@ -54,6 +56,9 @@ import java.util.Set; import javax.annotation.CheckReturnValue; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * A collection of expressions which read inputs, compute output expressions, * and optionally use a condition to filter rows. @@ -94,7 +99,7 @@ public class RexProgram { /** * Reference counts for each expression, computed on demand. */ - private int @Nullable [] refCounts; + private int @MonotonicNonNull[] refCounts; //~ Constructors ----------------------------------------------------------- @@ -212,7 +217,7 @@ public static RexProgram create( RelDataType inputRowType, List projectExprs, @Nullable RexNode conditionExpr, - @Nullable List fieldNames, + @Nullable List fieldNames, RexBuilder rexBuilder) { if (fieldNames == null) { fieldNames = Collections.nCopies(projectExprs.size(), null); @@ -433,7 +438,9 @@ public RelDataType getOutputRowType() { * or null if not known * @return Whether the program is valid */ - public boolean isValid(Litmus litmus, RelNode.@Nullable Context context) { + public boolean isValid( + @UnknownInitialization RexProgram this, + Litmus litmus, RelNode.@Nullable Context context) { if (inputRowType == null) { return litmus.fail(null); } @@ -674,7 +681,7 @@ public int[] getReferenceCounts() { return refCounts; } refCounts = new int[exprs.size()]; - ReferenceCounter refCounter = new ReferenceCounter(); + ReferenceCounter refCounter = new ReferenceCounter(refCounts); RexUtil.apply(refCounter, exprs, null); if (condition != null) { refCounter.visitLocalRef(condition); @@ -692,7 +699,7 @@ public boolean isConstant(RexNode ref) { return ref.accept(new ConstantFinder()); } - public RexNode gatherExpr(RexNode expr) { + public @Nullable RexNode gatherExpr(RexNode expr) { return expr.accept(new Marshaller()); } @@ -934,7 +941,7 @@ private class ConstantFinder extends RexUtil.ConstantFinder { * Given an expression in a program, creates a clone of the expression with * sub-expressions (represented by {@link RexLocalRef}s) fully expanded. */ - private class Marshaller extends RexVisitorImpl { + private class Marshaller extends RexVisitorImpl<@Nullable RexNode> { Marshaller() { super(false); } @@ -943,7 +950,7 @@ public RexNode visitInputRef(RexInputRef inputRef) { return inputRef; } - public RexNode visitLocalRef(RexLocalRef localRef) { + public @Nullable RexNode visitLocalRef(RexLocalRef localRef) { final RexNode expr = exprs.get(localRef.index); return expr.accept(this); } @@ -955,7 +962,7 @@ public RexNode visitLiteral(RexLiteral literal) { public RexNode visitCall(RexCall call) { final List newOperands = new ArrayList<>(); for (RexNode operand : call.getOperands()) { - newOperands.add(operand.accept(this)); + newOperands.add(castNonNull(operand.accept(this))); } return call.clone(call.getType(), newOperands); } @@ -980,7 +987,7 @@ public RexNode visitFieldAccess(RexFieldAccess fieldAccess) { final RexNode referenceExpr = fieldAccess.getReferenceExpr().accept(this); return new RexFieldAccess( - referenceExpr, + assertNonNull(referenceExpr, "referenceExpr must not be null"), fieldAccess.getField()); } } @@ -988,9 +995,12 @@ public RexNode visitFieldAccess(RexFieldAccess fieldAccess) { /** * Visitor which marks which expressions are used. */ - private class ReferenceCounter extends RexVisitorImpl { - ReferenceCounter() { + private static class ReferenceCounter extends RexVisitorImpl { + private final int[] refCounts; + + ReferenceCounter(int[] refCounts) { super(true); + this.refCounts = refCounts; } public Void visitLocalRef(RexLocalRef localRef) { diff --git a/core/src/main/java/org/apache/calcite/rex/RexProgramBuilder.java b/core/src/main/java/org/apache/calcite/rex/RexProgramBuilder.java index 9d92bb146d72..95dfe409fa87 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexProgramBuilder.java +++ b/core/src/main/java/org/apache/calcite/rex/RexProgramBuilder.java @@ -49,7 +49,7 @@ public class RexProgramBuilder { new HashMap<>(); private final List localRefList = new ArrayList<>(); private final List projectRefList = new ArrayList<>(); - private final List projectNameList = new ArrayList<>(); + private final List<@Nullable String> projectNameList = new ArrayList<>(); private final @Nullable RexSimplify simplify; private @Nullable RexLocalRef conditionRef = null; private boolean validating; @@ -204,7 +204,7 @@ public Void visitInputRef(RexInputRef input) { * be generated when the program is created * @return the ref created */ - public RexLocalRef addProject(RexNode expr, String name) { + public RexLocalRef addProject(RexNode expr, @Nullable String name) { final RexLocalRef ref = registerInput(expr); return addProject(ref.getIndex(), name); } @@ -217,7 +217,7 @@ public RexLocalRef addProject(RexNode expr, String name) { * will be generated when the program is created * @return the ref created */ - public RexLocalRef addProject(int ordinal, final String name) { + public RexLocalRef addProject(int ordinal, final @Nullable String name) { final RexLocalRef ref = localRefList.get(ordinal); projectRefList.add(ref); projectNameList.add(name); @@ -631,7 +631,7 @@ public static RexProgram normalize( private void add( List exprList, List projectRefList, - RexLocalRef conditionRef, + @Nullable RexLocalRef conditionRef, final RelDataType outputRowType, RexShuttle shuttle, boolean updateRefs) { diff --git a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java index 01d825e331a9..c8adf4ca7042 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java +++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java @@ -1208,7 +1208,7 @@ static boolean isSafeExpression(RexNode r) { return r.accept(SafeRexVisitor.INSTANCE); } - private static @Nullable RexNode simplifyBooleanCase(RexBuilder rexBuilder, + private static RexNode simplifyBooleanCase(RexBuilder rexBuilder, List inputBranches, RexUnknownAs unknownAs, RelDataType branchType) { RexNode result; @@ -1254,7 +1254,7 @@ static boolean isSafeExpression(RexNode r) { * to *

(p1 and x) or (p2 and y and not(p1)) or (true and z and not(p1) and not(p2))
*/ - private static @Nullable RexNode simplifyBooleanCaseGeneric(RexBuilder rexBuilder, + private static RexNode simplifyBooleanCaseGeneric(RexBuilder rexBuilder, List branches) { boolean booleanBranches = branches.stream() diff --git a/core/src/main/java/org/apache/calcite/rex/RexTableInputRef.java b/core/src/main/java/org/apache/calcite/rex/RexTableInputRef.java index e61c86cc2b3a..a27c73273cbe 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexTableInputRef.java +++ b/core/src/main/java/org/apache/calcite/rex/RexTableInputRef.java @@ -23,6 +23,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import java.util.List; +import java.util.Objects; /** * Variable which references a column of a table occurrence in a relational plan. @@ -61,7 +62,7 @@ private RexTableInputRef(RelTableRef tableRef, int index, RelDataType type) { } @Override public int hashCode() { - return digest.hashCode(); + return Objects.hashCode(digest); } public RelTableRef getTableRef() { 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 86ac3ac92051..d32be5269c1b 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java +++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java @@ -16,7 +16,6 @@ */ package org.apache.calcite.rex; -import org.apache.calcite.linq4j.Nullness; import org.apache.calcite.linq4j.function.Predicate1; import org.apache.calcite.plan.RelOptPredicateList; import org.apache.calcite.plan.RelOptUtil; @@ -69,8 +68,6 @@ import java.util.Set; import java.util.function.Predicate; import javax.annotation.Nonnull; -import javax.annotation.Nullable; - import static org.apache.calcite.linq4j.Nullness.castNonNull; @@ -1257,7 +1254,7 @@ private static void addAnd(ImmutableList.Builder builder, * Removes expressions that always evaluate to FALSE. * Flattens expressions that are ORs. */ - @Nonnull public static @Nullable RexNode composeDisjunction(RexBuilder rexBuilder, + public static RexNode composeDisjunction(RexBuilder rexBuilder, Iterable nodes) { final RexNode e = composeDisjunction(rexBuilder, nodes, false); return Objects.requireNonNull(e); diff --git a/core/src/main/java/org/apache/calcite/rex/RexWindowBound.java b/core/src/main/java/org/apache/calcite/rex/RexWindowBound.java index 3e4b1cb8f5e7..b9cbc1f0cff8 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexWindowBound.java +++ b/core/src/main/java/org/apache/calcite/rex/RexWindowBound.java @@ -18,7 +18,9 @@ import org.apache.calcite.sql.SqlNode; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; /** * Abstracts "XX PRECEDING/FOLLOWING" and "CURRENT ROW" bounds for windowed @@ -38,6 +40,9 @@ public static RexWindowBound create(SqlNode node, RexNode rexNode) { * Returns if the bound is unbounded. * @return if the bound is unbounded */ + @Pure + @EnsuresNonNullIf(expression = "getOffset()", result = false) + @SuppressWarnings("contracts.conditional.postcondition.not.satisfied") public boolean isUnbounded() { return false; } @@ -71,6 +76,7 @@ public boolean isCurrentRow() { * * @return offset from XX PRECEDING/FOLLOWING */ + @Pure public @Nullable RexNode getOffset() { return null; } diff --git a/core/src/main/java/org/apache/calcite/rex/RexWindowBounds.java b/core/src/main/java/org/apache/calcite/rex/RexWindowBounds.java index 9cada271384a..c7af903717f8 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexWindowBounds.java +++ b/core/src/main/java/org/apache/calcite/rex/RexWindowBounds.java @@ -52,7 +52,7 @@ private RexWindowBounds() { * @param rexNode offset value when bound is not UNBOUNDED/CURRENT ROW * @return window bound */ - public static RexWindowBound create(SqlNode node, RexNode rexNode) { + public static RexWindowBound create(SqlNode node, @Nullable RexNode rexNode) { if (SqlWindow.isUnboundedPreceding(node)) { return UNBOUNDED_PRECEDING; } @@ -62,6 +62,7 @@ public static RexWindowBound create(SqlNode node, RexNode rexNode) { if (SqlWindow.isCurrentRow(node)) { return CURRENT_ROW; } + assert rexNode != null : "offset value cannot be null for bounded window"; return new RexBoundedWindowBound((RexCall) rexNode); } diff --git a/core/src/main/java/org/apache/calcite/runtime/AbstractImmutableList.java b/core/src/main/java/org/apache/calcite/runtime/AbstractImmutableList.java index cc58a0013891..83877d6063c3 100644 --- a/core/src/main/java/org/apache/calcite/runtime/AbstractImmutableList.java +++ b/core/src/main/java/org/apache/calcite/runtime/AbstractImmutableList.java @@ -16,12 +16,16 @@ */ package org.apache.calcite.runtime; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import javax.annotation.Nonnull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Base class for lists whose contents are constant after creation. * @@ -86,8 +90,8 @@ public E remove(int index) { return toList().subList(fromIndex, toIndex); } - public boolean contains(Object o) { - return indexOf(o) >= 0; + public boolean contains(@Nullable Object o) { + return indexOf(castNonNull(o)) >= 0; } public boolean containsAll(@Nonnull Collection c) { @@ -99,7 +103,7 @@ public boolean containsAll(@Nonnull Collection c) { return true; } - public boolean remove(Object o) { + public boolean remove(@Nullable Object o) { throw new UnsupportedOperationException(); } } diff --git a/core/src/main/java/org/apache/calcite/runtime/ConsList.java b/core/src/main/java/org/apache/calcite/runtime/ConsList.java index 4a68164b078b..7f7c8712be7b 100644 --- a/core/src/main/java/org/apache/calcite/runtime/ConsList.java +++ b/core/src/main/java/org/apache/calcite/runtime/ConsList.java @@ -16,6 +16,7 @@ */ package org.apache.calcite.runtime; + import com.google.common.collect.ImmutableList; import org.checkerframework.checker.nullness.qual.Nullable; @@ -25,7 +26,8 @@ import java.util.Iterator; import java.util.List; import java.util.ListIterator; -import javax.annotation.Nonnull; + +import static org.apache.calcite.linq4j.Nullness.castNonNull; /** * List that consists of a head element and an immutable non-empty list. @@ -101,25 +103,25 @@ protected final List toList() { } } - @Override @Nonnull public ListIterator listIterator() { + @Override public ListIterator listIterator() { return toList().listIterator(); } - @Override @Nonnull public Iterator iterator() { + @Override public Iterator iterator() { return toList().iterator(); } - @Override @Nonnull public ListIterator listIterator(int index) { + @Override public ListIterator listIterator(int index) { return toList().listIterator(index); } - @Nonnull public Object[] toArray() { + public Object[] toArray() { return toList().toArray(); } - @Nonnull public T[] toArray(@Nonnull T[] a) { + public @Nullable T[] toArray(T @Nullable [] a) { final int s = size(); - if (s > a.length) { + if (s > castNonNull(a).length) { a = Arrays.copyOf(a, s); } else if (s < a.length) { a[s] = null; diff --git a/core/src/main/java/org/apache/calcite/runtime/FlatLists.java b/core/src/main/java/org/apache/calcite/runtime/FlatLists.java index 5df7529041e4..e9fb414adfb7 100644 --- a/core/src/main/java/org/apache/calcite/runtime/FlatLists.java +++ b/core/src/main/java/org/apache/calcite/runtime/FlatLists.java @@ -34,6 +34,8 @@ import java.util.Objects; import java.util.RandomAccess; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Space-efficient, comparable, immutable lists. */ @@ -247,7 +249,7 @@ private static ComparableList of_(List t) { } /** Returns a list that consists of a given list plus an element. */ - public static List append(List list, E e) { + public static List append(List list, E e) { if (list instanceof AbstractFlatList) { //noinspection unchecked return ((AbstractFlatList) list).append(e); @@ -259,13 +261,14 @@ public static List append(List list, E e) { /** Returns a list that consists of a given list plus an element, guaranteed * to be an {@link ImmutableList}. */ - public static ImmutableList append(ImmutableList list, E e) { + public static ImmutableList append(ImmutableList list, E e) { return ImmutableList.builder().addAll(list).add(e).build(); } /** Returns a map that consists of a given map plus an (key, value), * guaranteed to be an {@link ImmutableMap}. */ - public static ImmutableMap append(Map map, K k, V v) { + public static ImmutableMap append( + Map map, K k, V v) { final ImmutableMap.Builder builder = ImmutableMap.builder(); builder.put(k, v); map.forEach((k2, v2) -> { @@ -381,8 +384,8 @@ public int lastIndexOf(Object o) { } @SuppressWarnings({"unchecked" }) - public T2 @PolyNull [] toArray(T2 @PolyNull [] a) { - if (a.length < 1) { + public @Nullable T2[] toArray(T2 @Nullable [] a) { + if (castNonNull(a).length < 1) { // Make a new array of a's runtime type, but my contents: return (T2[]) Arrays.copyOf(toArray(), 1, a.getClass()); } @@ -390,8 +393,8 @@ public int lastIndexOf(Object o) { return a; } - public Object[] toArray() { - return new Object[] {t0}; + public @PolyNull Object[] toArray(Flat1List<@PolyNull T> this) { + return new Object[]{castNonNull(t0)}; } public int compareTo(List o) { @@ -513,8 +516,8 @@ public int lastIndexOf(Object o) { } @SuppressWarnings({"unchecked" }) - public T2 @PolyNull [] toArray(T2 @PolyNull [] a) { - if (a.length < 2) { + public @Nullable T2[] toArray(T2 @Nullable [] a) { + if (castNonNull(a).length < 2) { // Make a new array of a's runtime type, but my contents: return (T2[]) Arrays.copyOf(toArray(), 2, a.getClass()); } @@ -523,8 +526,8 @@ public int lastIndexOf(Object o) { return a; } - public Object[] toArray() { - return new Object[] {t0, t1}; + public @PolyNull Object[] toArray(Flat2List<@PolyNull T> this) { + return new Object[] {castNonNull(t0), castNonNull(t1)}; } public int compareTo(List o) { @@ -662,8 +665,8 @@ public int lastIndexOf(Object o) { } @SuppressWarnings({"unchecked" }) - public T2 @PolyNull [] toArray(T2 @PolyNull [] a) { - if (a.length < 3) { + public @Nullable T2[] toArray(T2 @Nullable [] a) { + if (castNonNull(a).length < 3) { // Make a new array of a's runtime type, but my contents: return (T2[]) Arrays.copyOf(toArray(), 3, a.getClass()); } @@ -673,8 +676,8 @@ public int lastIndexOf(Object o) { return a; } - public Object[] toArray() { - return new Object[] {t0, t1, t2}; + public @PolyNull Object[] toArray(Flat3List<@PolyNull T> this) { + return new Object[] {castNonNull(t0), castNonNull(t1), castNonNull(t2)}; } public int compareTo(List o) { @@ -830,8 +833,8 @@ public int lastIndexOf(Object o) { } @SuppressWarnings({"unchecked" }) - public T2 @PolyNull [] toArray(T2 @PolyNull [] a) { - if (a.length < 4) { + public @Nullable T2[] toArray(T2 @Nullable [] a) { + if (castNonNull(a).length < 4) { // Make a new array of a's runtime type, but my contents: return (T2[]) Arrays.copyOf(toArray(), 4, a.getClass()); } @@ -842,8 +845,8 @@ public int lastIndexOf(Object o) { return a; } - public Object[] toArray() { - return new Object[] {t0, t1, t2, t3}; + public @PolyNull Object[] toArray(Flat4List<@PolyNull T> this) { + return new Object[] {castNonNull(t0), castNonNull(t1), castNonNull(t2), castNonNull(t3)}; } public int compareTo(List o) { @@ -1017,8 +1020,8 @@ public int lastIndexOf(Object o) { } @SuppressWarnings({"unchecked" }) - public T2 @PolyNull [] toArray(T2 @PolyNull [] a) { - if (a.length < 5) { + public @Nullable T2[] toArray(T2 @Nullable [] a) { + if (castNonNull(a).length < 5) { // Make a new array of a's runtime type, but my contents: return (T2[]) Arrays.copyOf(toArray(), 5, a.getClass()); } @@ -1030,8 +1033,9 @@ public int lastIndexOf(Object o) { return a; } - public Object[] toArray() { - return new Object[] {t0, t1, t2, t3, t4}; + public @PolyNull Object[] toArray(Flat5List<@PolyNull T> this) { + return new Object[] {castNonNull(t0), castNonNull(t1), castNonNull(t2), castNonNull(t3), + castNonNull(t4)}; } public int compareTo(List o) { @@ -1224,8 +1228,8 @@ public int lastIndexOf(Object o) { } @SuppressWarnings({"unchecked" }) - public T2 @PolyNull [] toArray(T2 @PolyNull [] a) { - if (a.length < 6) { + public @Nullable T2[] toArray(T2 @Nullable [] a) { + if (castNonNull(a).length < 6) { // Make a new array of a's runtime type, but my contents: return (T2[]) Arrays.copyOf(toArray(), 6, a.getClass()); } @@ -1238,8 +1242,9 @@ public int lastIndexOf(Object o) { return a; } - public Object[] toArray() { - return new Object[] {t0, t1, t2, t3, t4, t5}; + public @PolyNull Object[] toArray(Flat6List<@PolyNull T> this) { + return new Object[] {castNonNull(t0), castNonNull(t1), castNonNull(t2), castNonNull(t3), + castNonNull(t4), castNonNull(t5)}; } public int compareTo(List o) { diff --git a/core/src/main/java/org/apache/calcite/runtime/Hook.java b/core/src/main/java/org/apache/calcite/runtime/Hook.java index ce681f3eaf4a..d81123b295f5 100644 --- a/core/src/main/java/org/apache/calcite/runtime/Hook.java +++ b/core/src/main/java/org/apache/calcite/runtime/Hook.java @@ -20,6 +20,7 @@ import org.apache.calcite.util.Holder; import org.apiguardian.api.API; +import org.checkerframework.checker.nullness.qual.Nullable; import java.util.ArrayList; import java.util.List; @@ -102,7 +103,7 @@ public enum Hook { private final List> handlers = new CopyOnWriteArrayList<>(); - private final ThreadLocal>> threadHandlers = + private final ThreadLocal<@Nullable List>> threadHandlers = ThreadLocal.withInitial(ArrayList::new); /** Adds a handler for this Hook. diff --git a/core/src/main/java/org/apache/calcite/runtime/Resources.java b/core/src/main/java/org/apache/calcite/runtime/Resources.java index f309f481eab4..8f15f46bbe45 100644 --- a/core/src/main/java/org/apache/calcite/runtime/Resources.java +++ b/core/src/main/java/org/apache/calcite/runtime/Resources.java @@ -38,7 +38,7 @@ * number and types of arguments to match the message. */ public class Resources { - private static final ThreadLocal MAP_THREAD_TO_LOCALE = + private static final ThreadLocal<@Nullable Locale> MAP_THREAD_TO_LOCALE = new ThreadLocal<>(); private Resources() {} diff --git a/core/src/main/java/org/apache/calcite/runtime/ResultSetEnumerable.java b/core/src/main/java/org/apache/calcite/runtime/ResultSetEnumerable.java index b29e890a27a0..2c434aa23a6a 100644 --- a/core/src/main/java/org/apache/calcite/runtime/ResultSetEnumerable.java +++ b/core/src/main/java/org/apache/calcite/runtime/ResultSetEnumerable.java @@ -27,6 +27,7 @@ import org.apache.calcite.linq4j.tree.Primitive; import org.apache.calcite.util.Static; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,6 +55,8 @@ import java.util.List; import javax.sql.DataSource; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Executes a SQL statement and returns the result as an {@link Enumerable}. * @@ -63,16 +66,16 @@ public class ResultSetEnumerable extends AbstractEnumerable { private final DataSource dataSource; private final String sql; private final Function1> rowBuilderFactory; - private final PreparedStatementEnricher preparedStatementEnricher; + private final @Nullable PreparedStatementEnricher preparedStatementEnricher; private static final Logger LOGGER = LoggerFactory.getLogger( ResultSetEnumerable.class); - private Long queryStart; + private @Nullable Long queryStart; private long timeout; private boolean timeoutSetFailed; - private static final Function1> AUTO_ROW_BUILDER_FACTORY = + private static final Function1> AUTO_ROW_BUILDER_FACTORY = resultSet -> { final ResultSetMetaData metaData; final int columnCount; @@ -92,9 +95,9 @@ public class ResultSetEnumerable extends AbstractEnumerable { }; } else { //noinspection unchecked - return (Function0) () -> { + return (Function0<@Nullable Object>) () -> { try { - final List list = new ArrayList<>(); + final List<@Nullable Object> list = new ArrayList<>(); for (int i = 0; i < columnCount; i++) { if (metaData.getColumnType(i + 1) == Types.TIMESTAMP) { long v = resultSet.getLong(i + 1); @@ -119,7 +122,7 @@ private ResultSetEnumerable( DataSource dataSource, String sql, Function1> rowBuilderFactory, - PreparedStatementEnricher preparedStatementEnricher) { + @Nullable PreparedStatementEnricher preparedStatementEnricher) { this.dataSource = dataSource; this.sql = sql; this.rowBuilderFactory = rowBuilderFactory; @@ -196,8 +199,9 @@ public static PreparedStatementEnricher createEnricher(Integer[] indexes, /** Assigns a value to a dynamic parameter in a prepared statement, calling * the appropriate {@code setXxx} method based on the type of the value. */ private static void setDynamicParam(PreparedStatement preparedStatement, - int i, Object value) throws SQLException { + int i, @Nullable Object value) throws SQLException { if (value == null) { + // TODO: use proper type instead of ANY preparedStatement.setObject(i, null, SqlType.ANY.id); } else if (value instanceof Timestamp) { preparedStatement.setTimestamp(i, (Timestamp) value); @@ -268,6 +272,7 @@ private Enumerator enumeratorBasedOnStatement() { return new ResultSetEnumerator<>(resultSet, rowBuilderFactory); } else { Integer updateCount = statement.getUpdateCount(); + //noinspection unchecked return Linq4j.singletonEnumerator((T) updateCount); } } catch (SQLException e) { @@ -285,7 +290,7 @@ private Enumerator enumeratorBasedOnPreparedStatement() { connection = dataSource.getConnection(); preparedStatement = connection.prepareStatement(sql); setTimeoutIfPossible(preparedStatement); - preparedStatementEnricher.enrich(preparedStatement); + castNonNull(preparedStatementEnricher).enrich(preparedStatement); if (preparedStatement.execute()) { final ResultSet resultSet = preparedStatement.getResultSet(); preparedStatement = null; @@ -293,6 +298,7 @@ private Enumerator enumeratorBasedOnPreparedStatement() { return new ResultSetEnumerator<>(resultSet, rowBuilderFactory); } else { Integer updateCount = preparedStatement.getUpdateCount(); + //noinspection unchecked return Linq4j.singletonEnumerator((T) updateCount); } } catch (SQLException e) { @@ -304,7 +310,7 @@ private Enumerator enumeratorBasedOnPreparedStatement() { } private void setTimeoutIfPossible(Statement statement) throws SQLException { - if (timeout == 0) { + if (timeout == 0 || queryStart == null) { return; } long now = System.currentTimeMillis(); @@ -329,7 +335,7 @@ private void setTimeoutIfPossible(Statement statement) throws SQLException { } } - private void closeIfPossible(Connection connection, Statement statement) { + private void closeIfPossible(@Nullable Connection connection, @Nullable Statement statement) { if (statement != null) { try { statement.close(); @@ -352,7 +358,7 @@ private void closeIfPossible(Connection connection, Statement statement) { * @param element type */ private static class ResultSetEnumerator implements Enumerator { private final Function0 rowBuilder; - private ResultSet resultSet; + private @Nullable ResultSet resultSet; ResultSetEnumerator( ResultSet resultSet, @@ -361,13 +367,17 @@ private static class ResultSetEnumerator implements Enumerator { this.rowBuilder = rowBuilderFactory.apply(resultSet); } + private ResultSet resultSet() { + return castNonNull(resultSet); + } + public T current() { return rowBuilder.apply(); } public boolean moveNext() { try { - return resultSet.next(); + return resultSet().next(); } catch (SQLException e) { throw new RuntimeException(e); } @@ -375,7 +385,7 @@ public boolean moveNext() { public void reset() { try { - resultSet.beforeFirst(); + resultSet().beforeFirst(); } catch (SQLException e) { throw new RuntimeException(e); } @@ -402,7 +412,7 @@ public void close() { } } - private static Function1> + private static Function1> primitiveRowBuilderFactory(final Primitive[] primitives) { return resultSet -> { final ResultSetMetaData metaData; @@ -424,9 +434,9 @@ public void close() { }; } //noinspection unchecked - return (Function0) () -> { + return (Function0<@Nullable Object>) () -> { try { - final List list = new ArrayList<>(); + final List<@Nullable Object> list = new ArrayList<>(); for (int i = 0; i < columnCount; i++) { list.add(primitives[i].jdbcGet(resultSet, i + 1)); } diff --git a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java index 5c1fcce7948a..2fb9214374c9 100644 --- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java +++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java @@ -27,7 +27,6 @@ import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.linq4j.Enumerator; import org.apache.calcite.linq4j.Linq4j; -import org.apache.calcite.linq4j.Nullness; import org.apache.calcite.linq4j.function.Deterministic; import org.apache.calcite.linq4j.function.Experimental; import org.apache.calcite.linq4j.function.Function1; @@ -146,7 +145,7 @@ public Enumerator enumerator() { *

This is a straw man of an implementation whose main goal is to prove * that sequences can be parsed, validated and planned. A real application * will want persistent values for sequences, shared among threads. */ - private static final ThreadLocal> THREAD_SEQUENCES = + private static final ThreadLocal<@Nullable Map> THREAD_SEQUENCES = ThreadLocal.withInitial(HashMap::new); private static final Pattern PATTERN_0_STAR_E = Pattern.compile("0*E"); @@ -2212,7 +2211,8 @@ public static int unixDate(int v) { } public static @PolyNull Long toTimestampWithLocalTimeZone(@PolyNull String v, TimeZone timeZone) { - return v == null ? castNonNull(null) : new TimestampWithTimeZoneString(v + " " + timeZone.getID()) + return v == null ? castNonNull(null) + : new TimestampWithTimeZoneString(v + " " + timeZone.getID()) .withTimeZone(DateTimeUtils.UTC_ZONE) .getLocalTimestampString() .getMillisSinceEpoch(); diff --git a/core/src/main/java/org/apache/calcite/runtime/XmlFunctions.java b/core/src/main/java/org/apache/calcite/runtime/XmlFunctions.java index 67783744a0e6..291f800ec313 100644 --- a/core/src/main/java/org/apache/calcite/runtime/XmlFunctions.java +++ b/core/src/main/java/org/apache/calcite/runtime/XmlFunctions.java @@ -20,6 +20,7 @@ import org.apache.commons.lang3.StringUtils; +import org.checkerframework.checker.nullness.qual.Nullable; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; @@ -54,9 +55,9 @@ */ public class XmlFunctions { - private static final ThreadLocal XPATH_FACTORY = + private static final ThreadLocal<@Nullable XPathFactory> XPATH_FACTORY = ThreadLocal.withInitial(XPathFactory::newInstance); - private static final ThreadLocal TRANSFORMER_FACTORY = + private static final ThreadLocal<@Nullable TransformerFactory> TRANSFORMER_FACTORY = ThreadLocal.withInitial(TransformerFactory::newInstance); private static final Pattern VALID_NAMESPACE_PATTERN = Pattern diff --git a/core/src/main/java/org/apache/calcite/schema/Path.java b/core/src/main/java/org/apache/calcite/schema/Path.java index 89d7070bf186..924935213cb0 100644 --- a/core/src/main/java/org/apache/calcite/schema/Path.java +++ b/core/src/main/java/org/apache/calcite/schema/Path.java @@ -18,6 +18,8 @@ import org.apache.calcite.util.Pair; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import java.util.RandomAccess; @@ -31,7 +33,7 @@ * [(root, ""), (child, "foo")]. * */ -public interface Path extends List>, RandomAccess { +public interface Path extends List>, RandomAccess { /** Returns the parent path, or null if the path is empty. */ Path parent(); @@ -39,5 +41,5 @@ public interface Path extends List>, RandomAccess { List names(); /** Returns the schemas of this path. */ - List schemas(); + List<@Nullable Schema> schemas(); } diff --git a/core/src/main/java/org/apache/calcite/schema/SchemaPlus.java b/core/src/main/java/org/apache/calcite/schema/SchemaPlus.java index 39752ecd5aef..b1f4bb263690 100644 --- a/core/src/main/java/org/apache/calcite/schema/SchemaPlus.java +++ b/core/src/main/java/org/apache/calcite/schema/SchemaPlus.java @@ -80,7 +80,7 @@ public interface SchemaPlus extends Schema { boolean isMutable(); /** Returns an underlying object. */ - T unwrap(Class clazz); + @Nullable T unwrap(Class clazz); void setPath(ImmutableList> path); 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 4e15c67ad11e..86ada7245f21 100644 --- a/core/src/main/java/org/apache/calcite/schema/Schemas.java +++ b/core/src/main/java/org/apache/calcite/schema/Schemas.java @@ -69,7 +69,7 @@ private Schemas() { throw new AssertionError("no instances!"); } - public static CalciteSchema.FunctionEntry resolve( + public static CalciteSchema.@Nullable FunctionEntry resolve( RelDataTypeFactory typeFactory, String name, Collection functionEntries, @@ -509,7 +509,7 @@ public static String uniqueTableName(CalciteSchema schema, String base) { /** Creates a path with a given list of names starting from a given root * schema. */ public static Path path(CalciteSchema rootSchema, Iterable names) { - final ImmutableList.Builder> builder = + final ImmutableList.Builder> builder = ImmutableList.builder(); Schema schema = rootSchema.plus(); final Iterator iterator = names.iterator(); @@ -531,7 +531,7 @@ public static Path path(CalciteSchema rootSchema, Iterable names) { } } - public static PathImpl path(ImmutableList> build) { + public static PathImpl path(ImmutableList> build) { return new PathImpl(build); } @@ -575,13 +575,13 @@ private static class DummyDataContext implements DataContext { /** Implementation of {@link Path}. */ private static class PathImpl - extends AbstractList> implements Path { - private final ImmutableList> pairs; + extends AbstractList> implements Path { + private final ImmutableList> pairs; private static final PathImpl EMPTY = new PathImpl(ImmutableList.of()); - PathImpl(ImmutableList> pairs) { + PathImpl(ImmutableList> pairs) { this.pairs = pairs; } @@ -595,7 +595,7 @@ private static class PathImpl return pairs.hashCode(); } - public Pair get(int index) { + public Pair get(int index) { return pairs.get(index); } @@ -622,7 +622,7 @@ public int size() { }; } - public List schemas() { + public List<@Nullable Schema> schemas() { return Pair.right(pairs); } } diff --git a/core/src/main/java/org/apache/calcite/schema/Table.java b/core/src/main/java/org/apache/calcite/schema/Table.java index 79f55f69f189..d8d53d8e1697 100644 --- a/core/src/main/java/org/apache/calcite/schema/Table.java +++ b/core/src/main/java/org/apache/calcite/schema/Table.java @@ -22,6 +22,8 @@ import org.apache.calcite.sql.SqlCall; import org.apache.calcite.sql.SqlNode; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Table. * @@ -79,5 +81,5 @@ public interface Table { * @return true iff the given aggregate call is valid */ boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, - SqlNode parent, CalciteConnectionConfig config); + @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config); } diff --git a/core/src/main/java/org/apache/calcite/schema/impl/AbstractTable.java b/core/src/main/java/org/apache/calcite/schema/impl/AbstractTable.java index a50c21058725..1cdc0c8967c0 100644 --- a/core/src/main/java/org/apache/calcite/schema/impl/AbstractTable.java +++ b/core/src/main/java/org/apache/calcite/schema/impl/AbstractTable.java @@ -60,7 +60,7 @@ public Schema.TableType getJdbcTableType() { } @Override public boolean rolledUpColumnValidInsideAgg(String column, - SqlCall call, SqlNode parent, CalciteConnectionConfig config) { + SqlCall call, @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return true; } } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlBasicCall.java b/core/src/main/java/org/apache/calcite/sql/SqlBasicCall.java index 634cb5cf5009..ae86d3c0fab7 100755 --- a/core/src/main/java/org/apache/calcite/sql/SqlBasicCall.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlBasicCall.java @@ -24,25 +24,27 @@ import java.util.List; import java.util.Objects; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Implementation of {@link SqlCall} that keeps its operands in an array. */ public class SqlBasicCall extends SqlCall { private SqlOperator operator; - public final SqlNode[] operands; + public final @Nullable SqlNode[] operands; private final @Nullable SqlLiteral functionQuantifier; private final boolean expanded; public SqlBasicCall( SqlOperator operator, - SqlNode[] operands, + @Nullable SqlNode[] operands, SqlParserPos pos) { this(operator, operands, pos, false, null); } public SqlBasicCall( SqlOperator operator, - SqlNode[] operands, + @Nullable SqlNode[] operands, SqlParserPos pos, boolean expanded, @Nullable SqlLiteral functionQualifier) { @@ -73,17 +75,18 @@ public SqlOperator getOperator() { return operator; } - public SqlNode[] getOperands() { + public @Nullable SqlNode[] getOperands() { return operands; } + @SuppressWarnings("nullness") public List getOperandList() { return UnmodifiableArrayList.of(operands); // not immutable, but quick } @SuppressWarnings("unchecked") @Override public S operand(int i) { - return (S) operands[i]; + return (S) castNonNull(operands[i]); } @Override public int operandCount() { diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCall.java b/core/src/main/java/org/apache/calcite/sql/SqlCall.java index 658dd79e36c2..e06db8a67465 100755 --- a/core/src/main/java/org/apache/calcite/sql/SqlCall.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlCall.java @@ -27,12 +27,15 @@ import org.apache.calcite.util.Litmus; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.annotation.Nonnull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * A SqlCall is a call to an {@link SqlOperator operator}. * (Operators can be used to describe any syntactic construct, so in practice, @@ -77,7 +80,9 @@ public void setOperand(int i, @Nullable SqlNode operand) { @SuppressWarnings("unchecked") public S operand(int i) { - return (S) getOperandList().get(i); + // Note: in general, null elements exist in the list, however, the code + // assumes operand(..) is non-nullable, so we add a cast here + return (S) castNonNull(getOperandList().get(i)); } public int operandCount() { @@ -141,7 +146,7 @@ public R accept(SqlVisitor visitor) { return visitor.visit(this); } - public boolean equalsDeep(SqlNode node, Litmus litmus) { + public boolean equalsDeep(@Nullable SqlNode node, Litmus litmus) { if (node == this) { return true; } @@ -205,6 +210,7 @@ && operandCount() == 1) { return false; } + @Pure public @Nullable SqlLiteral getFunctionQuantifier() { return null; } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java b/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java index 154f14e7f163..8dd03ee67a95 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java @@ -188,7 +188,7 @@ public R accept(SqlVisitor visitor) { return visitor.visit(this); } - public boolean equalsDeep(SqlNode node, Litmus litmus) { + public boolean equalsDeep(@Nullable SqlNode node, Litmus litmus) { if (!(node instanceof SqlDataTypeSpec)) { return litmus.fail("{} != {}", this, node); } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDelete.java b/core/src/main/java/org/apache/calcite/sql/SqlDelete.java index f81d64573ef9..d67ab067021e 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlDelete.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlDelete.java @@ -26,6 +26,7 @@ import java.util.List; + /** * A SqlDelete is a node of a parse tree which represents a DELETE * statement. @@ -35,18 +36,18 @@ public class SqlDelete extends SqlCall { new SqlSpecialOperator("DELETE", SqlKind.DELETE); SqlNode targetTable; - SqlNode condition; - SqlSelect sourceSelect; - SqlIdentifier alias; + @Nullable SqlNode condition; + @Nullable SqlSelect sourceSelect; + @Nullable SqlIdentifier alias; //~ Constructors ----------------------------------------------------------- public SqlDelete( SqlParserPos pos, SqlNode targetTable, - SqlNode condition, - SqlSelect sourceSelect, - SqlIdentifier alias) { + @Nullable SqlNode condition, + @Nullable SqlSelect sourceSelect, + @Nullable SqlIdentifier alias) { super(pos); this.targetTable = targetTable; this.condition = condition; @@ -64,10 +65,12 @@ public SqlOperator getOperator() { return OPERATOR; } + @SuppressWarnings("nullness") public List getOperandList() { return ImmutableNullableList.of(targetTable, condition, alias); } + @SuppressWarnings("assignment.type.incompatible") @Override public void setOperand(int i, @Nullable SqlNode operand) { switch (i) { case 0: @@ -97,7 +100,7 @@ public SqlNode getTargetTable() { /** * Returns the alias for the target table of the deletion. */ - public SqlIdentifier getAlias() { + public @Nullable SqlIdentifier getAlias() { return alias; } @@ -107,7 +110,7 @@ public SqlIdentifier getAlias() { * @return the condition expression for the data to be deleted, or null for * all rows in the table */ - public SqlNode getCondition() { + public @Nullable SqlNode getCondition() { return condition; } @@ -118,7 +121,7 @@ public SqlNode getCondition() { * * @return the source SELECT for the data to be inserted */ - public SqlSelect getSourceSelect() { + public @Nullable SqlSelect getSourceSelect() { return sourceSelect; } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDescribeSchema.java b/core/src/main/java/org/apache/calcite/sql/SqlDescribeSchema.java index bceaad734ad1..0ef0a54ac0e1 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlDescribeSchema.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlDescribeSchema.java @@ -23,6 +23,7 @@ import java.util.List; + /** * A SqlDescribeSchema is a node of a parse tree that represents a * {@code DESCRIBE SCHEMA} statement. @@ -31,8 +32,9 @@ public class SqlDescribeSchema extends SqlCall { public static final SqlSpecialOperator OPERATOR = new SqlSpecialOperator("DESCRIBE_SCHEMA", SqlKind.DESCRIBE_SCHEMA) { + @SuppressWarnings("argument.type.incompatible") @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { return new SqlDescribeSchema(pos, (SqlIdentifier) operands[0]); } }; @@ -51,6 +53,7 @@ public SqlDescribeSchema(SqlParserPos pos, SqlIdentifier schema) { schema.unparse(writer, leftPrec, rightPrec); } + @SuppressWarnings("assignment.type.incompatible") @Override public void setOperand(int i, @Nullable SqlNode operand) { switch (i) { case 0: diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDescribeTable.java b/core/src/main/java/org/apache/calcite/sql/SqlDescribeTable.java index 9f2567df6dd6..2cff6f3a677b 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlDescribeTable.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlDescribeTable.java @@ -22,6 +22,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; import java.util.List; +import java.util.Objects; + /** * A SqlDescribeTable is a node of a parse tree that represents a @@ -31,22 +33,23 @@ public class SqlDescribeTable extends SqlCall { public static final SqlSpecialOperator OPERATOR = new SqlSpecialOperator("DESCRIBE_TABLE", SqlKind.DESCRIBE_TABLE) { + @SuppressWarnings("argument.type.incompatible") @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { return new SqlDescribeTable(pos, (SqlIdentifier) operands[0], - (SqlIdentifier) operands[1]); + (@Nullable SqlIdentifier) operands[1]); } }; SqlIdentifier table; - SqlIdentifier column; + @Nullable SqlIdentifier column; /** Creates a SqlDescribeTable. */ public SqlDescribeTable(SqlParserPos pos, SqlIdentifier table, - SqlIdentifier column) { + @Nullable SqlIdentifier column) { super(pos); - this.table = table; + this.table = Objects.requireNonNull(table); this.column = column; } @@ -59,6 +62,7 @@ public SqlDescribeTable(SqlParserPos pos, } } + @SuppressWarnings("assignment.type.incompatible") @Override public void setOperand(int i, @Nullable SqlNode operand) { switch (i) { case 0: @@ -76,6 +80,7 @@ public SqlDescribeTable(SqlParserPos pos, return OPERATOR; } + @SuppressWarnings("nullness") @Override public List getOperandList() { return ImmutableNullableList.of(table, column); } @@ -84,7 +89,7 @@ public SqlIdentifier getTable() { return table; } - public SqlIdentifier getColumn() { + public @Nullable SqlIdentifier getColumn() { return column; } } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java index 122432cf9523..2ffd7ecf4f38 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java @@ -31,7 +31,7 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.parser.SqlParserPos; -import org.apache.calcite.sql.type.BasicSqlType; +import org.apache.calcite.sql.type.AbstractSqlType; import org.apache.calcite.sql.type.SqlTypeUtil; import org.apache.calcite.sql.validate.SqlConformance; import org.apache.calcite.sql.validate.SqlConformanceEnum; @@ -40,6 +40,7 @@ import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableSet; +import org.checkerframework.dataflow.qual.Pure; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -591,7 +592,7 @@ public void quoteStringLiteralUnicode(StringBuilder buf, String val) { * Converts a string literal back into a string. For example, 'can''t * run' becomes can't run. */ - public String unquoteStringLiteral(String val) { + public @Nullable String unquoteStringLiteral(@Nullable String val) { if (val != null && val.startsWith(literalQuoteString) && val.endsWith(literalEndQuoteString)) { @@ -696,6 +697,7 @@ public DatabaseProduct getDatabaseProduct() { * Returns whether the dialect supports character set names as part of a * data type, for instance {@code VARCHAR(30) CHARACTER SET `ISO-8859-1`}. */ + @Pure public boolean supportsCharSet() { return true; } @@ -771,8 +773,9 @@ public boolean supportsDataType(RelDataType type) { * implementation, this is the case for the NULL type, and therefore * {@code CAST(NULL AS )} is rendered as {@code NULL}. */ public @Nullable SqlNode getCastSpec(RelDataType type) { - if (type instanceof BasicSqlType) { - int maxPrecision = -1; + int maxPrecision = -1; + if (type instanceof AbstractSqlType) { + System.out.println("type.getSqlTypeName() = " + type.getSqlTypeName().getName()); switch (type.getSqlTypeName()) { case NULL: return null; @@ -882,13 +885,13 @@ public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, * @param offset Number of rows to skip before emitting, or null * @param fetch Number of rows to fetch, or null */ - public void unparseTopN(SqlWriter writer, SqlNode offset, SqlNode fetch) { + public void unparseTopN(SqlWriter writer, @Nullable SqlNode offset, @Nullable SqlNode fetch) { } /** Unparses offset/fetch using ANSI standard "OFFSET offset ROWS FETCH NEXT * fetch ROWS ONLY" syntax. */ - protected final void unparseFetchUsingAnsi(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + protected final void unparseFetchUsingAnsi(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { Preconditions.checkArgument(fetch != null || offset != null); if (offset != null) { writer.newlineAndIndent(); @@ -913,14 +916,14 @@ protected final void unparseFetchUsingAnsi(SqlWriter writer, SqlNode offset, } /** Unparses offset/fetch using "LIMIT fetch OFFSET offset" syntax. */ - protected final void unparseFetchUsingLimit(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + protected final void unparseFetchUsingLimit(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { Preconditions.checkArgument(fetch != null || offset != null); unparseLimit(writer, fetch); unparseOffset(writer, offset); } - protected final void unparseLimit(SqlWriter writer, SqlNode fetch) { + protected final void unparseLimit(SqlWriter writer, @Nullable SqlNode fetch) { if (fetch != null) { writer.newlineAndIndent(); final SqlWriter.Frame fetchFrame = @@ -931,7 +934,7 @@ protected final void unparseLimit(SqlWriter writer, SqlNode fetch) { } } - protected final void unparseOffset(SqlWriter writer, SqlNode offset) { + protected final void unparseOffset(SqlWriter writer, @Nullable SqlNode offset) { if (offset != null) { writer.newlineAndIndent(); final SqlWriter.Frame offsetFrame = @@ -1281,10 +1284,13 @@ public enum DatabaseProduct { private final Supplier dialect; + @SuppressWarnings("argument.type.incompatible") DatabaseProduct(String databaseProductName, @Nullable String quoteString, NullCollation nullCollation) { Objects.requireNonNull(databaseProductName); Objects.requireNonNull(nullCollation); + // Note: below lambda accesses uninitialized DatabaseProduct.this, so it might be + // worth refactoring dialect = Suppliers.memoize(() -> { final SqlDialect dialect = SqlDialectFactoryImpl.simple(DatabaseProduct.this); diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java b/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java index d150794c9121..9a8b5ff7b15e 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlDialectFactoryImpl.java @@ -51,6 +51,7 @@ import org.apache.calcite.sql.dialect.TeradataSqlDialect; import org.apache.calcite.sql.dialect.VerticaSqlDialect; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -240,7 +241,7 @@ private String getIdentifierQuoteString(DatabaseMetaData databaseMetaData) { } /** Returns a basic dialect for a given product, or null if none is known. */ - static SqlDialect simple(SqlDialect.DatabaseProduct databaseProduct) { + static @Nullable SqlDialect simple(SqlDialect.DatabaseProduct databaseProduct) { switch (databaseProduct) { case ACCESS: return AccessSqlDialect.DEFAULT; diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java b/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java index 1e2a084bec9c..373bd8b9f2d2 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java @@ -23,6 +23,8 @@ import org.apache.calcite.sql.validate.SqlValidatorScope; import org.apache.calcite.util.Litmus; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * A SqlDynamicParam represents a dynamic parameter marker in an * SQL statement. The textual order in which dynamic parameters appear within an @@ -76,7 +78,7 @@ public R accept(SqlVisitor visitor) { return visitor.visit(this); } - public boolean equalsDeep(SqlNode node, Litmus litmus) { + public boolean equalsDeep(@Nullable SqlNode node, Litmus litmus) { if (!(node instanceof SqlDynamicParam)) { return litmus.fail("{} != {}", this, node); } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlExplain.java b/core/src/main/java/org/apache/calcite/sql/SqlExplain.java index 106378ab2339..8ff0d06af46f 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlExplain.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlExplain.java @@ -23,6 +23,8 @@ import java.util.List; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; + /** * A SqlExplain is a node of a parse tree which represents an * EXPLAIN PLAN statement. @@ -30,8 +32,9 @@ public class SqlExplain extends SqlCall { public static final SqlSpecialOperator OPERATOR = new SqlSpecialOperator("EXPLAIN", SqlKind.EXPLAIN) { + @SuppressWarnings("argument.type.incompatible") @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { return new SqlExplain(pos, operands[0], (SqlLiteral) operands[1], (SqlLiteral) operands[2], (SqlLiteral) operands[3], 0); } @@ -84,6 +87,7 @@ public List getOperandList() { return ImmutableNullableList.of(explicandum, detailLevel, depth, format); } + @SuppressWarnings("assignment.type.incompatible") @Override public void setOperand(int i, @Nullable SqlNode operand) { switch (i) { case 0: @@ -114,14 +118,18 @@ public SqlNode getExplicandum() { * Return the detail level to be generated. */ public SqlExplainLevel getDetailLevel() { - return detailLevel.symbolValue(SqlExplainLevel.class); + return assertNonNull( + detailLevel.symbolValue(SqlExplainLevel.class), + "detailLevel must not be null"); } /** * Returns the level of abstraction at which this plan should be displayed. */ public Depth getDepth() { - return depth.symbolValue(Depth.class); + return assertNonNull( + depth.symbolValue(Depth.class), + "depth must not be null"); } /** @@ -149,7 +157,9 @@ public boolean withType() { * Returns the desired output format. */ public SqlExplainFormat getFormat() { - return format.symbolValue(SqlExplainFormat.class); + return assertNonNull( + format.symbolValue(SqlExplainFormat.class), + "format must not be null"); } /** diff --git a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java index 49bb7967796c..7a7ac192de60 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java @@ -31,11 +31,13 @@ import org.apache.calcite.util.Util; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; import java.util.List; import java.util.Objects; import javax.annotation.Nonnull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; import static org.apache.calcite.util.Static.RESOURCE; /** @@ -166,7 +168,7 @@ public SqlSyntax getSyntax() { * {@link #getOperandTypeChecker()}. */ @Deprecated // to be removed before 2.0 public List getParamNames() { - return Functions.generate(getParamTypes().size(), i -> "arg" + i); + return Functions.generate(castNonNull(getParamTypes()).size(), i -> "arg" + i); } public void unparse( @@ -189,6 +191,7 @@ public void unparse( * ALL quantifier. The default is false; some aggregate * functions return true. */ + @Pure public boolean isQuantifierAllowed() { return false; } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java b/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java index 7bbf668aefff..6eafb6c8afef 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java @@ -303,7 +303,7 @@ public void validateExpr(SqlValidator validator, SqlValidatorScope scope) { validator.validateIdentifier(this, scope); } - public boolean equalsDeep(SqlNode node, Litmus litmus) { + public boolean equalsDeep(@Nullable SqlNode node, Litmus litmus) { if (!(node instanceof SqlIdentifier)) { return litmus.fail("{} != {}", this, node); } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlInsert.java b/core/src/main/java/org/apache/calcite/sql/SqlInsert.java index 501822e58509..909eb1312da5 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlInsert.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlInsert.java @@ -25,6 +25,7 @@ import java.util.List; + /** * A SqlInsert is a node of a parse tree which represents an INSERT * statement. @@ -32,9 +33,10 @@ public class SqlInsert extends SqlCall { public static final SqlSpecialOperator OPERATOR = new SqlSpecialOperator("INSERT", SqlKind.INSERT) { + @SuppressWarnings("argument.type.incompatible") @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, SqlParserPos pos, - SqlNode... operands) { + @Nullable SqlNode... operands) { return new SqlInsert( pos, (SqlNodeList) operands[0], @@ -47,7 +49,7 @@ public class SqlInsert extends SqlCall { SqlNodeList keywords; SqlNode targetTable; SqlNode source; - SqlNodeList columnList; + @Nullable SqlNodeList columnList; //~ Constructors ----------------------------------------------------------- @@ -55,7 +57,7 @@ public SqlInsert(SqlParserPos pos, SqlNodeList keywords, SqlNode targetTable, SqlNode source, - SqlNodeList columnList) { + @Nullable SqlNodeList columnList) { super(pos); this.keywords = keywords; this.targetTable = targetTable; @@ -74,6 +76,7 @@ public SqlOperator getOperator() { return OPERATOR; } + @SuppressWarnings("nullness") public List getOperandList() { return ImmutableNullableList.of(keywords, targetTable, source, columnList); } @@ -87,6 +90,7 @@ public final boolean isUpsert() { return getModifierNode(SqlInsertKeyword.UPSERT) != null; } + @SuppressWarnings("assignment.type.incompatible") @Override public void setOperand(int i, @Nullable SqlNode operand) { switch (i) { case 0: @@ -129,11 +133,11 @@ public void setSource(SqlSelect source) { * Returns the list of target column names, or null for all columns in the * target table. */ - public SqlNodeList getTargetColumnList() { + public @Nullable SqlNodeList getTargetColumnList() { return columnList; } - public final SqlNode getModifierNode(SqlInsertKeyword modifier) { + public final @Nullable SqlNode getModifierNode(SqlInsertKeyword modifier) { for (SqlNode keyword : keywords) { SqlInsertKeyword keyword2 = ((SqlLiteral) keyword).symbolValue(SqlInsertKeyword.class); diff --git a/core/src/main/java/org/apache/calcite/sql/SqlIntervalLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlIntervalLiteral.java index 6a2a8dcd75e5..bdb2d432f22f 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlIntervalLiteral.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlIntervalLiteral.java @@ -24,6 +24,8 @@ import java.util.Objects; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * A SQL literal representing a time interval. * @@ -55,7 +57,7 @@ protected SqlIntervalLiteral( } private SqlIntervalLiteral( - IntervalValue intervalValue, + @Nullable IntervalValue intervalValue, SqlTypeName sqlTypeName, SqlParserPos pos) { super( @@ -79,7 +81,7 @@ public void unparse( @SuppressWarnings("deprecation") public int signum() { - return ((IntervalValue) value).signum(); + return ((IntervalValue) castNonNull(value)).signum(); } //~ Inner Classes ---------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java b/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java index 10360faec43a..5b012fac424c 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java @@ -192,7 +192,7 @@ public R accept(SqlVisitor visitor) { return visitor.visit(this); } - public boolean equalsDeep(SqlNode node, Litmus litmus) { + public boolean equalsDeep(@Nullable SqlNode node, Litmus litmus) { final String thisString = this.toString(); final String thatString = node.toString(); if (!thisString.equals(thatString)) { diff --git a/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java b/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java index 246daaa6352d..488cfd565101 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java @@ -440,7 +440,7 @@ private static String constructFuncList(String... functionNames) { public SqlCall createCall( @Nullable SqlLiteral functionQualifier, SqlParserPos pos, - SqlNode... operands) { + @Nullable SqlNode... operands) { thisOperands = operands; return super.createCall(functionQualifier, pos, operands); } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlJoin.java b/core/src/main/java/org/apache/calcite/sql/SqlJoin.java index 413b384ae77f..bce3d1be18ec 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlJoin.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlJoin.java @@ -28,6 +28,8 @@ import java.util.List; import java.util.Objects; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; + /** * Parse tree node representing a {@code JOIN} clause. */ @@ -84,11 +86,13 @@ public SqlOperator getOperator() { return SqlKind.JOIN; } + @SuppressWarnings("nullness") public List getOperandList() { return ImmutableNullableList.of(left, natural, joinType, right, conditionType, condition); } + @SuppressWarnings("assignment.type.incompatible") @Override public void setOperand(int i, @Nullable SqlNode operand) { switch (i) { case 0: @@ -120,7 +124,9 @@ public List getOperandList() { /** Returns a {@link JoinConditionType}, never null. */ public final JoinConditionType getConditionType() { - return conditionType.symbolValue(JoinConditionType.class); + return assertNonNull( + conditionType.symbolValue(JoinConditionType.class), + "conditionType must not be null"); } public SqlLiteral getConditionTypeNode() { @@ -129,7 +135,9 @@ public SqlLiteral getConditionTypeNode() { /** Returns a {@link JoinType}, never null. */ public final JoinType getJoinType() { - return joinType.symbolValue(JoinType.class); + return assertNonNull( + joinType.symbolValue(JoinType.class), + "joinType must not be null"); } public SqlLiteral getJoinTypeNode() { @@ -181,10 +189,11 @@ public SqlSyntax getSyntax() { return SqlSyntax.SPECIAL; } + @SuppressWarnings("argument.type.incompatible") public SqlCall createCall( @Nullable SqlLiteral functionQualifier, SqlParserPos pos, - SqlNode... operands) { + @Nullable SqlNode... operands) { assert functionQualifier == null; return new SqlJoin(pos, operands[0], (SqlLiteral) operands[1], (SqlLiteral) operands[2], operands[3], (SqlLiteral) operands[4], diff --git a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java index 79a046689ce2..bb8d1121a9f4 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java @@ -49,6 +49,7 @@ import javax.annotation.Nonnull; import static org.apache.calcite.linq4j.Nullness.assertNonNull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; import static org.apache.calcite.util.Static.RESOURCE; /** @@ -384,13 +385,13 @@ public SqlLiteral clone(SqlParserPos pos) { /** Returns the value as a symbol. */ @Deprecated // to be removed before 2.0 - public > E symbolValue_() { + public > @Nullable E symbolValue_() { //noinspection unchecked - return (E) value; + return (@Nullable E) value; } /** Returns the value as a symbol. */ - public > E symbolValue(Class class_) { + public > @Nullable E symbolValue(Class class_) { return class_.cast(value); } @@ -433,7 +434,7 @@ public static SqlSampleSpec sampleValue(SqlNode node) { *

  • Otherwise throws {@link IllegalArgumentException}. * */ - public static Comparable value(SqlNode node) + public static @Nullable Comparable value(SqlNode node) throws IllegalArgumentException { if (node instanceof SqlLiteral) { final SqlLiteral literal = (SqlLiteral) node; @@ -565,7 +566,7 @@ public R accept(SqlVisitor visitor) { return visitor.visit(this); } - public boolean equalsDeep(SqlNode node, Litmus litmus) { + public boolean equalsDeep(@Nullable SqlNode node, Litmus litmus) { if (!(node instanceof SqlLiteral)) { return litmus.fail("{} != {}", this, node); } @@ -612,7 +613,7 @@ public static SqlLiteral createUnknown(SqlParserPos pos) { * * @see #symbolValue(Class) */ - public static SqlLiteral createSymbol(Enum o, SqlParserPos pos) { + public static SqlLiteral createSymbol(@Nullable Enum o, SqlParserPos pos) { return new SqlLiteral(o, SqlTypeName.SYMBOL, pos); } @@ -700,14 +701,14 @@ public long longValue(boolean exact) { */ @Deprecated // to be removed before 2.0 public int signum() { - return bigDecimalValue().compareTo( + return castNonNull(bigDecimalValue()).compareTo( BigDecimal.ZERO); } /** * Returns a numeric literal's value as a {@link BigDecimal}. */ - public BigDecimal bigDecimalValue() { + public @Nullable BigDecimal bigDecimalValue() { switch (typeName) { case DECIMAL: case DOUBLE: diff --git a/core/src/main/java/org/apache/calcite/sql/SqlMatchRecognize.java b/core/src/main/java/org/apache/calcite/sql/SqlMatchRecognize.java index 1aad9bdcc31f..482f3c9a09a2 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlMatchRecognize.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlMatchRecognize.java @@ -31,6 +31,7 @@ import java.util.Objects; import javax.annotation.Nonnull; + /** * SqlNode for MATCH_RECOGNIZE clause. */ @@ -64,19 +65,19 @@ public class SqlMatchRecognize extends SqlCall { private SqlLiteral strictEnd; private SqlNodeList patternDefList; private SqlNodeList measureList; - private SqlNode after; + private @Nullable SqlNode after; private SqlNodeList subsetList; - private SqlLiteral rowsPerMatch; + private @Nullable SqlLiteral rowsPerMatch; private SqlNodeList partitionList; private SqlNodeList orderList; - private SqlLiteral interval; + private @Nullable SqlLiteral interval; /** Creates a SqlMatchRecognize. */ public SqlMatchRecognize(SqlParserPos pos, SqlNode tableRef, SqlNode pattern, SqlLiteral strictStart, SqlLiteral strictEnd, SqlNodeList patternDefList, - SqlNodeList measureList, SqlNode after, SqlNodeList subsetList, - SqlLiteral rowsPerMatch, SqlNodeList partitionList, - SqlNodeList orderList, SqlLiteral interval) { + SqlNodeList measureList, @Nullable SqlNode after, SqlNodeList subsetList, + @Nullable SqlLiteral rowsPerMatch, SqlNodeList partitionList, + SqlNodeList orderList, @Nullable SqlLiteral interval) { super(pos); this.tableRef = Objects.requireNonNull(tableRef); this.pattern = Objects.requireNonNull(pattern); @@ -105,6 +106,7 @@ public SqlMatchRecognize(SqlParserPos pos, SqlNode tableRef, SqlNode pattern, return SqlKind.MATCH_RECOGNIZE; } + @SuppressWarnings("nullness") @Override public List getOperandList() { return ImmutableNullableList.of(tableRef, pattern, strictStart, strictEnd, patternDefList, measureList, after, subsetList, partitionList, orderList); @@ -119,6 +121,7 @@ public SqlMatchRecognize(SqlParserPos pos, SqlNode tableRef, SqlNode pattern, validator.validateMatchRecognize(this); } + @SuppressWarnings("assignment.type.incompatible") @Override public void setOperand(int i, @Nullable SqlNode operand) { switch (i) { case OPERAND_TABLE_REF: @@ -189,7 +192,7 @@ public SqlLiteral getStrictEnd() { return measureList; } - public SqlNode getAfter() { + public @Nullable SqlNode getAfter() { return after; } @@ -197,7 +200,7 @@ public SqlNodeList getSubsetList() { return subsetList; } - public SqlLiteral getRowsPerMatch() { + public @Nullable SqlLiteral getRowsPerMatch() { return rowsPerMatch; } @@ -209,7 +212,7 @@ public SqlNodeList getOrderList() { return orderList; } - public SqlLiteral getInterval() { + public @Nullable SqlLiteral getInterval() { return interval; } @@ -268,10 +271,11 @@ private SqlMatchRecognizeOperator() { return SqlSyntax.SPECIAL; } + @SuppressWarnings("argument.type.incompatible") @Override public SqlCall createCall( @Nullable SqlLiteral functionQualifier, SqlParserPos pos, - SqlNode... operands) { + @Nullable SqlNode... operands) { assert functionQualifier == null; assert operands.length == 12; diff --git a/core/src/main/java/org/apache/calcite/sql/SqlMerge.java b/core/src/main/java/org/apache/calcite/sql/SqlMerge.java index 8609ac7a9248..295a72e14926 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlMerge.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlMerge.java @@ -27,6 +27,7 @@ import java.util.List; + /** * A SqlMerge is a node of a parse tree which represents a MERGE * statement. @@ -38,10 +39,10 @@ public class SqlMerge extends SqlCall { SqlNode targetTable; SqlNode condition; SqlNode source; - SqlUpdate updateCall; - SqlInsert insertCall; - SqlSelect sourceSelect; - SqlIdentifier alias; + @Nullable SqlUpdate updateCall; + @Nullable SqlInsert insertCall; + @Nullable SqlSelect sourceSelect; + @Nullable SqlIdentifier alias; //~ Constructors ----------------------------------------------------------- @@ -49,10 +50,10 @@ public SqlMerge(SqlParserPos pos, SqlNode targetTable, SqlNode condition, SqlNode source, - SqlUpdate updateCall, - SqlInsert insertCall, - SqlSelect sourceSelect, - SqlIdentifier alias) { + @Nullable SqlUpdate updateCall, + @Nullable SqlInsert insertCall, + @Nullable SqlSelect sourceSelect, + @Nullable SqlIdentifier alias) { super(pos); this.targetTable = targetTable; this.condition = condition; @@ -73,11 +74,13 @@ public SqlOperator getOperator() { return SqlKind.MERGE; } - public List getOperandList() { + @SuppressWarnings("nullness") + public List<@Nullable SqlNode> getOperandList() { return ImmutableNullableList.of(targetTable, condition, source, updateCall, insertCall, sourceSelect, alias); } + @SuppressWarnings("assignment.type.incompatible") @Override public void setOperand(int i, @Nullable SqlNode operand) { switch (i) { case 0: @@ -91,13 +94,13 @@ public List getOperandList() { source = operand; break; case 3: - updateCall = (SqlUpdate) operand; + updateCall = (@Nullable SqlUpdate) operand; break; case 4: - insertCall = (SqlInsert) operand; + insertCall = (@Nullable SqlInsert) operand; break; case 5: - sourceSelect = (SqlSelect) operand; + sourceSelect = (@Nullable SqlSelect) operand; break; case 6: alias = (SqlIdentifier) operand; @@ -113,7 +116,7 @@ public SqlNode getTargetTable() { } /** Returns the alias for the target table of this MERGE. */ - public SqlIdentifier getAlias() { + public @Nullable SqlIdentifier getAlias() { return alias; } @@ -127,12 +130,12 @@ public void setSourceTableRef(SqlNode tableRef) { } /** Returns the UPDATE statement for this MERGE. */ - public SqlUpdate getUpdateCall() { + public @Nullable SqlUpdate getUpdateCall() { return updateCall; } /** Returns the INSERT statement for this MERGE. */ - public SqlInsert getInsertCall() { + public @Nullable SqlInsert getInsertCall() { return insertCall; } @@ -149,7 +152,7 @@ public SqlNode getCondition() { * * @return the source SELECT for the data to be updated */ - public SqlSelect getSourceSelect() { + public @Nullable SqlSelect getSourceSelect() { return sourceSelect; } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlNode.java b/core/src/main/java/org/apache/calcite/sql/SqlNode.java index 3b2bc0ee8116..3b2794aa7b21 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlNode.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlNode.java @@ -28,6 +28,8 @@ import org.apache.calcite.util.Litmus; import org.apache.calcite.util.Util; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -296,7 +298,7 @@ public void validateExpr( * (2 + 3), because the '+' operator is left-associative
  • * */ - public abstract boolean equalsDeep(SqlNode node, Litmus litmus); + public abstract boolean equalsDeep(@Nullable SqlNode node, Litmus litmus); @Deprecated // to be removed before 2.0 public final boolean equalsDeep(SqlNode node, boolean fail) { diff --git a/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java b/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java index 937945d5f2e5..20c157644674 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java @@ -24,11 +24,15 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * A SqlNodeList is a list of {@link SqlNode}s. It is also a * {@link SqlNode}, so may appear in a parse tree. @@ -43,7 +47,7 @@ public class SqlNodeList extends SqlNode implements Iterable { */ public static final SqlNodeList EMPTY = new SqlNodeList(SqlParserPos.ZERO) { - public void add(SqlNode node) { + @Override public void add(SqlNode node) { throw new UnsupportedOperationException(); } }; @@ -62,7 +66,9 @@ public void add(SqlNode node) { //~ Instance fields -------------------------------------------------------- - private final List list; + // Sometimes null values are present in the list, however, it is assumed that callers would + // perform all the required null-checks. + private final List<@Nullable SqlNode> list; //~ Constructors ----------------------------------------------------------- @@ -87,11 +93,12 @@ public SqlNodeList( //~ Methods ---------------------------------------------------------------- - // implement Iterable - public Iterator iterator() { + @SuppressWarnings("return.type.incompatible") + @Override public Iterator iterator() { return list.iterator(); } + @SuppressWarnings("return.type.incompatible") public List getList() { return list; } @@ -100,23 +107,24 @@ public void add(SqlNode node) { list.add(node); } - public SqlNodeList clone(SqlParserPos pos) { + @SuppressWarnings("argument.type.incompatible") + @Override public SqlNodeList clone(SqlParserPos pos) { return new SqlNodeList(list, pos); } public SqlNode get(int n) { - return list.get(n); + return castNonNull(list.get(n)); } public SqlNode set(int n, SqlNode node) { - return list.set(n, node); + return castNonNull(list.set(n, node)); } public int size() { return list.size(); } - public void unparse( + @Override public void unparse( SqlWriter writer, int leftPrec, int rightPrec) { @@ -137,17 +145,20 @@ void andOrList(SqlWriter writer, SqlBinaryOperator sepOp) { writer.list(SqlWriter.FrameTypeEnum.WHERE_LIST, sepOp, this); } - public void validate(SqlValidator validator, SqlValidatorScope scope) { + @Override public void validate(SqlValidator validator, SqlValidatorScope scope) { for (SqlNode child : list) { + if (child == null) { + continue; + } child.validate(validator, scope); } } - public R accept(SqlVisitor visitor) { + @Override public R accept(SqlVisitor visitor) { return visitor.visit(this); } - public boolean equalsDeep(SqlNode node, Litmus litmus) { + @Override public boolean equalsDeep(@Nullable SqlNode node, Litmus litmus) { if (!(node instanceof SqlNodeList)) { return litmus.fail("{} != {}", this, node); } @@ -158,6 +169,13 @@ public boolean equalsDeep(SqlNode node, Litmus litmus) { for (int i = 0; i < list.size(); i++) { SqlNode thisChild = list.get(i); final SqlNode thatChild = that.list.get(i); + if (thisChild == null) { + if (thatChild == null) { + continue; + } else { + return litmus.fail(null); + } + } if (!thisChild.equalsDeep(thatChild, litmus)) { return litmus.fail(null); } @@ -165,6 +183,7 @@ public boolean equalsDeep(SqlNode node, Litmus litmus) { return litmus.succeed(); } + @SuppressWarnings("return.type.incompatible") public SqlNode[] toArray() { return list.toArray(new SqlNode[0]); } @@ -201,7 +220,7 @@ public static SqlNodeList of(SqlNode node1, SqlNode node2, SqlNode... nodes) { return list; } - public void validateExpr(SqlValidator validator, SqlValidatorScope scope) { + @Override public void validateExpr(SqlValidator validator, SqlValidatorScope scope) { // While a SqlNodeList is not always a valid expression, this // implementation makes that assumption. It just validates the members // of the list. @@ -216,6 +235,9 @@ public void validateExpr(SqlValidator validator, SqlValidatorScope scope) { // SqlNodeList(SqlLiteral(10), SqlLiteral(20)) } for (SqlNode node : list) { + if (node == null) { + continue; + } node.validateExpr(validator, scope); } } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java index b6a7dd432a25..8140c77bcd05 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java @@ -46,6 +46,7 @@ import java.util.function.Supplier; import static org.apache.calcite.linq4j.Nullness.assertNonNull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; import static org.apache.calcite.util.Static.RESOURCE; /** @@ -245,7 +246,7 @@ public int getRightPrec() { public SqlCall createCall( @Nullable SqlLiteral functionQualifier, SqlParserPos pos, - SqlNode... operands) { + @Nullable SqlNode... operands) { pos = pos.plusAll(Arrays.asList(operands)); return new SqlBasicCall(this, operands, pos, false, functionQualifier); } @@ -529,7 +530,7 @@ public RelDataType deriveType( argTypes, null, null, getSyntax(), getKind(), validator.getCatalogReader().nameMatcher(), false); - ((SqlBasicCall) call).setOperator(sqlOperator); + ((SqlBasicCall) call).setOperator(castNonNull(sqlOperator)); RelDataType type = call.getOperator().validateOperands(validator, scope, call); // Validate and determine coercibility and resulting collation diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOrderBy.java b/core/src/main/java/org/apache/calcite/sql/SqlOrderBy.java index 11a42c6f15f3..eff92b088ebb 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlOrderBy.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlOrderBy.java @@ -23,6 +23,7 @@ import java.util.List; + /** * Parse tree node that represents an {@code ORDER BY} on a query other than a * {@code SELECT} (e.g. {@code VALUES} or {@code UNION}). @@ -33,8 +34,9 @@ */ public class SqlOrderBy extends SqlCall { public static final SqlSpecialOperator OPERATOR = new Operator() { + @SuppressWarnings("argument.type.incompatible") @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { return new SqlOrderBy(pos, operands[0], (SqlNodeList) operands[1], operands[2], operands[3]); } @@ -42,13 +44,13 @@ public class SqlOrderBy extends SqlCall { public final SqlNode query; public final SqlNodeList orderList; - public final SqlNode offset; - public final SqlNode fetch; + public final @Nullable SqlNode offset; + public final @Nullable SqlNode fetch; //~ Constructors ----------------------------------------------------------- public SqlOrderBy(SqlParserPos pos, SqlNode query, SqlNodeList orderList, - SqlNode offset, SqlNode fetch) { + @Nullable SqlNode offset, @Nullable SqlNode fetch) { super(pos); this.query = query; this.orderList = orderList; @@ -66,6 +68,7 @@ public SqlOperator getOperator() { return OPERATOR; } + @SuppressWarnings("nullness") public List getOperandList() { return ImmutableNullableList.of(query, orderList, offset, fetch); } 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 131b00d75d82..8dcf88121587 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlSelect.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlSelect.java @@ -92,6 +92,7 @@ public SqlOperator getOperator() { return SqlKind.SELECT; } + @SuppressWarnings("nullness") @Override public List getOperandList() { return ImmutableNullableList.of(keywordList, selectList, from, where, groupBy, having, windowDecls, orderBy, offset, fetch, hints); 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 b07e54c25443..747c02f73dbf 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java @@ -62,7 +62,7 @@ public SqlSyntax getSyntax() { public SqlCall createCall( @Nullable SqlLiteral functionQualifier, SqlParserPos pos, - SqlNode... operands) { + @Nullable SqlNode... operands) { assert functionQualifier == null; return new SqlSelect(pos, (SqlNodeList) operands[0], diff --git a/core/src/main/java/org/apache/calcite/sql/SqlSetOption.java b/core/src/main/java/org/apache/calcite/sql/SqlSetOption.java index 85fa243b0d8d..c8d280e86661 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlSetOption.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlSetOption.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.List; + /** * SQL parse tree node to represent {@code SET} and {@code RESET} statements, * optionally preceded by {@code ALTER SYSTEM} or {@code ALTER SESSION}. @@ -62,8 +63,9 @@ public class SqlSetOption extends SqlAlter { public static final SqlSpecialOperator OPERATOR = new SqlSpecialOperator("SET_OPTION", SqlKind.SET_OPTION) { + @SuppressWarnings("argument.type.incompatible") @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { final SqlNode scopeNode = operands[0]; return new SqlSetOption(pos, scopeNode == null ? null : scopeNode.toString(), @@ -79,7 +81,7 @@ public class SqlSetOption extends SqlAlter { * a {@link org.apache.calcite.sql.SqlIdentifier} with one * part. Reserved words (currently just 'ON') are converted to * identifiers by the parser. */ - SqlNode value; + @Nullable SqlNode value; /** * Creates a node. @@ -90,8 +92,8 @@ public class SqlSetOption extends SqlAlter { * @param value Value of option, as an identifier or literal, may be null. * If null, assume RESET command, else assume SET command. */ - public SqlSetOption(SqlParserPos pos, String scope, SqlIdentifier name, - SqlNode value) { + public SqlSetOption(SqlParserPos pos, @Nullable String scope, SqlIdentifier name, + @Nullable SqlNode value) { super(pos, scope); this.scope = scope; this.name = name; @@ -157,7 +159,9 @@ public SqlSetOption(SqlParserPos pos, String scope, SqlIdentifier name, @Override public void validate(SqlValidator validator, SqlValidatorScope scope) { - validator.validate(value); + if (value != null) { + validator.validate(value); + } } public SqlIdentifier getName() { @@ -168,7 +172,7 @@ public void setName(SqlIdentifier name) { this.name = name; } - public SqlNode getValue() { + public @Nullable SqlNode getValue() { return value; } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlSnapshot.java b/core/src/main/java/org/apache/calcite/sql/SqlSnapshot.java index e5b3d82e0438..84e3e8ba42e6 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlSnapshot.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlSnapshot.java @@ -95,10 +95,11 @@ private SqlSnapshotOperator() { return SqlSyntax.SPECIAL; } + @SuppressWarnings("argument.type.incompatible") @Override public SqlCall createCall( @Nullable SqlLiteral functionQualifier, SqlParserPos pos, - SqlNode... operands) { + @Nullable SqlNode... operands) { assert functionQualifier == null; assert operands.length == 2; return new SqlSnapshot(pos, operands[0], operands[1]); diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java b/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java index 0270a433f64c..cda687a32474 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java @@ -27,6 +27,7 @@ import java.util.List; + /** * A SqlUpdate is a node of a parse tree which represents an UPDATE * statement. @@ -38,9 +39,9 @@ public class SqlUpdate extends SqlCall { SqlNode targetTable; SqlNodeList targetColumnList; SqlNodeList sourceExpressionList; - SqlNode condition; - SqlSelect sourceSelect; - SqlIdentifier alias; + @Nullable SqlNode condition; + @Nullable SqlSelect sourceSelect; + @Nullable SqlIdentifier alias; //~ Constructors ----------------------------------------------------------- @@ -48,9 +49,9 @@ public SqlUpdate(SqlParserPos pos, SqlNode targetTable, SqlNodeList targetColumnList, SqlNodeList sourceExpressionList, - SqlNode condition, - SqlSelect sourceSelect, - SqlIdentifier alias) { + @Nullable SqlNode condition, + @Nullable SqlSelect sourceSelect, + @Nullable SqlIdentifier alias) { super(pos); this.targetTable = targetTable; this.targetColumnList = targetColumnList; @@ -71,7 +72,8 @@ public SqlOperator getOperator() { return OPERATOR; } - public List getOperandList() { + @SuppressWarnings("nullness") + public List<@Nullable SqlNode> getOperandList() { return ImmutableNullableList.of(targetTable, targetColumnList, sourceExpressionList, condition, alias); } @@ -108,7 +110,7 @@ public SqlNode getTargetTable() { } /** Returns the alias for the target table of this UPDATE. */ - public SqlIdentifier getAlias() { + public @Nullable SqlIdentifier getAlias() { return alias; } @@ -132,7 +134,7 @@ public SqlNodeList getSourceExpressionList() { * @return the condition expression for the data to be updated, or null for * all rows in the table */ - public SqlNode getCondition() { + public @Nullable SqlNode getCondition() { return condition; } @@ -143,7 +145,7 @@ public SqlNode getCondition() { * * @return the source SELECT for the data to be updated */ - public SqlSelect getSourceSelect() { + public @Nullable SqlSelect getSourceSelect() { return sourceSelect; } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java index 208d2893feba..16dcc4bbed56 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java @@ -52,6 +52,7 @@ import com.google.common.collect.Lists; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.PolyNull; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -999,7 +1000,7 @@ public static void validateCharset(ByteString value, Charset charset) { /** If a node is "AS", returns the underlying expression; otherwise returns * the node. */ - public static @Nullable SqlNode stripAs(@Nullable SqlNode node) { + public static @PolyNull SqlNode stripAs(@PolyNull SqlNode node) { if (node != null && node.getKind() == SqlKind.AS) { return ((SqlCall) node).operand(0); } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlWindow.java b/core/src/main/java/org/apache/calcite/sql/SqlWindow.java index ecb9674af337..05bafc417cec 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlWindow.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlWindow.java @@ -39,6 +39,7 @@ import java.util.List; +import static org.apache.calcite.linq4j.Nullness.castNonNull; import static org.apache.calcite.util.Static.RESOURCE; /** @@ -150,11 +151,13 @@ public SqlOperator getOperator() { return SqlKind.WINDOW; } + @SuppressWarnings("nullness") public List getOperandList() { return ImmutableNullableList.of(declName, refName, partitionList, orderList, isRows, lowerBound, upperBound, allowPartial); } + @SuppressWarnings("assignment.type.incompatible") @Override public void setOperand(int i, @Nullable SqlNode operand) { switch (i) { case 0: @@ -331,7 +334,7 @@ static void checkSpecialLiterals(SqlWindow window, SqlValidator validator) { if (Bound.CURRENT_ROW == lowerLitType) { if (null != upperOp) { if (upperOp == PRECEDING_OPERATOR) { - throw validator.newValidationError(upperBound, + throw validator.newValidationError(castNonNull(upperBound), RESOURCE.currentRowPrecedingError()); } } @@ -339,12 +342,12 @@ static void checkSpecialLiterals(SqlWindow window, SqlValidator validator) { if (lowerOp == FOLLOWING_OPERATOR) { if (null != upperOp) { if (upperOp == PRECEDING_OPERATOR) { - throw validator.newValidationError(upperBound, + throw validator.newValidationError(castNonNull(upperBound), RESOURCE.followingBeforePrecedingError()); } } else if (null != upperLitType) { if (Bound.CURRENT_ROW == upperLitType) { - throw validator.newValidationError(upperBound, + throw validator.newValidationError(castNonNull(upperBound), RESOURCE.currentRowFollowingError()); } } @@ -502,7 +505,7 @@ private static boolean setOperand(@Nullable SqlNode clonedOperand, @Nullable Sql * * @return boolean true if all nodes in the subtree are equal */ - @Override public boolean equalsDeep(SqlNode node, Litmus litmus) { + @Override public boolean equalsDeep(@Nullable SqlNode node, Litmus litmus) { // This is the difference over super.equalsDeep. It skips // operands[0] the declared name fo this window. We only want // to check the window components. @@ -809,10 +812,11 @@ public SqlSyntax getSyntax() { return SqlSyntax.SPECIAL; } + @SuppressWarnings("argument.type.incompatible") public SqlCall createCall( @Nullable SqlLiteral functionQualifier, SqlParserPos pos, - SqlNode... operands) { + @Nullable SqlNode... operands) { assert functionQualifier == null; assert operands.length == 8; return create( diff --git a/core/src/main/java/org/apache/calcite/sql/SqlWith.java b/core/src/main/java/org/apache/calcite/sql/SqlWith.java index 21b68bbde7dc..53be56488eb6 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlWith.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlWith.java @@ -26,6 +26,7 @@ import java.util.List; + /** * The WITH clause of a query. It wraps a SELECT, UNION, or INTERSECT. */ @@ -109,8 +110,9 @@ public void unparse( } + @SuppressWarnings("argument.type.incompatible") @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { return new SqlWith(pos, (SqlNodeList) operands[0], operands[1]); } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlWithItem.java b/core/src/main/java/org/apache/calcite/sql/SqlWithItem.java index fb1f3ff91ea6..58bd229b7521 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlWithItem.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlWithItem.java @@ -23,17 +23,18 @@ import java.util.List; + /** * An item in a WITH clause of a query. * It has a name, an optional column list, and a query. */ public class SqlWithItem extends SqlCall { public SqlIdentifier name; - public SqlNodeList columnList; // may be null + public @Nullable SqlNodeList columnList; // may be null public SqlNode query; public SqlWithItem(SqlParserPos pos, SqlIdentifier name, - SqlNodeList columnList, SqlNode query) { + @Nullable SqlNodeList columnList, SqlNode query) { super(pos); this.name = name; this.columnList = columnList; @@ -46,17 +47,19 @@ public SqlWithItem(SqlParserPos pos, SqlIdentifier name, return SqlKind.WITH_ITEM; } + @SuppressWarnings("nullness") public List getOperandList() { return ImmutableNullableList.of(name, columnList, query); } + @SuppressWarnings("assignment.type.incompatible") @Override public void setOperand(int i, @Nullable SqlNode operand) { switch (i) { case 0: name = (SqlIdentifier) operand; break; case 1: - columnList = (SqlNodeList) operand; + columnList = (@Nullable SqlNodeList) operand; break; case 2: query = operand; @@ -98,8 +101,9 @@ public void unparse( withItem.query.unparse(writer, 10, 10); } + @SuppressWarnings("argument.type.incompatible") @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { assert functionQualifier == null; assert operands.length == 3; return new SqlWithItem(pos, (SqlIdentifier) operands[0], diff --git a/core/src/main/java/org/apache/calcite/sql/SqlWriter.java b/core/src/main/java/org/apache/calcite/sql/SqlWriter.java index b26489ed2ae0..af9cdedcc65b 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlWriter.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlWriter.java @@ -19,6 +19,8 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.util.SqlString; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.function.Consumer; /** @@ -373,14 +375,14 @@ public String getName() { /** * Prints the OFFSET/FETCH clause. */ - void fetchOffset(SqlNode fetch, SqlNode offset); + void fetchOffset(@Nullable SqlNode fetch, @Nullable SqlNode offset); /** * Prints the TOP(n) clause. * * @see #fetchOffset */ - void topN(SqlNode fetch, SqlNode offset); + void topN(@Nullable SqlNode fetch, @Nullable SqlNode offset); /** * Prints a new line, and indents. @@ -463,7 +465,7 @@ public String getName() { * * @param frame The frame which was created by {@link #startList}. */ - void endList(Frame frame); + void endList(@Nullable Frame frame); /** * Writes a list. diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlAttributeDefinition.java b/core/src/main/java/org/apache/calcite/sql/ddl/SqlAttributeDefinition.java index 1d7c88bda9ef..02905e3957b1 100644 --- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlAttributeDefinition.java +++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlAttributeDefinition.java @@ -29,6 +29,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -41,12 +43,12 @@ public class SqlAttributeDefinition extends SqlCall { public final SqlIdentifier name; public final SqlDataTypeSpec dataType; - final SqlNode expression; - final SqlCollation collation; + final @Nullable SqlNode expression; + final @Nullable SqlCollation collation; /** Creates a SqlAttributeDefinition; use {@link SqlDdlNodes#attribute}. */ SqlAttributeDefinition(SqlParserPos pos, SqlIdentifier name, - SqlDataTypeSpec dataType, SqlNode expression, SqlCollation collation) { + SqlDataTypeSpec dataType, @Nullable SqlNode expression, @Nullable SqlCollation collation) { super(pos); this.name = name; this.dataType = dataType; diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCheckConstraint.java b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCheckConstraint.java index a685c62c99a5..a74ed3e90ef7 100644 --- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCheckConstraint.java +++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCheckConstraint.java @@ -26,6 +26,8 @@ import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.util.ImmutableNullableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -37,11 +39,11 @@ public class SqlCheckConstraint extends SqlCall { private static final SqlSpecialOperator OPERATOR = new SqlSpecialOperator("CHECK", SqlKind.CHECK); - private final SqlIdentifier name; + private final @Nullable SqlIdentifier name; private final SqlNode expression; /** Creates a SqlCheckConstraint; use {@link SqlDdlNodes#check}. */ - SqlCheckConstraint(SqlParserPos pos, SqlIdentifier name, + SqlCheckConstraint(SqlParserPos pos, @Nullable SqlIdentifier name, SqlNode expression) { super(pos); this.name = name; // may be null @@ -52,6 +54,7 @@ public class SqlCheckConstraint extends SqlCall { return OPERATOR; } + @SuppressWarnings("nullness") @Override public List getOperandList() { return ImmutableNullableList.of(name, expression); } diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlColumnDeclaration.java b/core/src/main/java/org/apache/calcite/sql/ddl/SqlColumnDeclaration.java index 83cb03733592..1c5015634ea7 100644 --- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlColumnDeclaration.java +++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlColumnDeclaration.java @@ -29,6 +29,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -42,12 +44,12 @@ public class SqlColumnDeclaration extends SqlCall { public final SqlIdentifier name; public final SqlDataTypeSpec dataType; - public final SqlNode expression; + public final @Nullable SqlNode expression; public final ColumnStrategy strategy; /** Creates a SqlColumnDeclaration; use {@link SqlDdlNodes#column}. */ SqlColumnDeclaration(SqlParserPos pos, SqlIdentifier name, - SqlDataTypeSpec dataType, SqlNode expression, + SqlDataTypeSpec dataType, @Nullable SqlNode expression, ColumnStrategy strategy) { super(pos); this.name = name; diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateForeignSchema.java b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateForeignSchema.java index 9c6b667990b8..62f757d7a5ae 100644 --- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateForeignSchema.java +++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateForeignSchema.java @@ -29,19 +29,24 @@ import org.apache.calcite.util.Pair; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import org.checkerframework.checker.nullness.qual.Nullable; import java.util.AbstractList; import java.util.List; import java.util.Objects; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Parse tree for {@code CREATE FOREIGN SCHEMA} statement. */ public class SqlCreateForeignSchema extends SqlCreate { public final SqlIdentifier name; - public final SqlNode type; - public final SqlNode library; - private final SqlNodeList optionList; + public final @Nullable SqlNode type; + public final @Nullable SqlNode library; + private final @Nullable SqlNodeList optionList; private static final SqlOperator OPERATOR = new SqlSpecialOperator("CREATE FOREIGN SCHEMA", @@ -49,8 +54,8 @@ public class SqlCreateForeignSchema extends SqlCreate { /** Creates a SqlCreateForeignSchema. */ SqlCreateForeignSchema(SqlParserPos pos, boolean replace, boolean ifNotExists, - SqlIdentifier name, SqlNode type, SqlNode library, - SqlNodeList optionList) { + SqlIdentifier name, @Nullable SqlNode type, @Nullable SqlNode library, + @Nullable SqlNodeList optionList) { super(OPERATOR, pos, replace, ifNotExists); this.name = Objects.requireNonNull(name); this.type = type; @@ -60,6 +65,7 @@ public class SqlCreateForeignSchema extends SqlCreate { this.optionList = optionList; // may be null } + @SuppressWarnings("nullness") @Override public List getOperandList() { return ImmutableNullableList.of(name, type, library, optionList); } @@ -104,11 +110,14 @@ public List> options() { } private static List> options( - final SqlNodeList optionList) { + final @Nullable SqlNodeList optionList) { + if (optionList == null) { + return ImmutableList.of(); + } return new AbstractList>() { public Pair get(int index) { - return Pair.of((SqlIdentifier) optionList.get(index * 2), - optionList.get(index * 2 + 1)); + return Pair.of((SqlIdentifier) castNonNull(optionList.get(index * 2)), + castNonNull(optionList.get(index * 2 + 1))); } public int size() { diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateMaterializedView.java b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateMaterializedView.java index 26fd93327ea3..19691f02eeab 100644 --- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateMaterializedView.java +++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateMaterializedView.java @@ -27,6 +27,8 @@ import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.util.ImmutableNullableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import java.util.Objects; @@ -35,7 +37,7 @@ */ public class SqlCreateMaterializedView extends SqlCreate { public final SqlIdentifier name; - public final SqlNodeList columnList; + public final @Nullable SqlNodeList columnList; public final SqlNode query; private static final SqlOperator OPERATOR = @@ -44,7 +46,7 @@ public class SqlCreateMaterializedView extends SqlCreate { /** Creates a SqlCreateView. */ SqlCreateMaterializedView(SqlParserPos pos, boolean replace, - boolean ifNotExists, SqlIdentifier name, SqlNodeList columnList, + boolean ifNotExists, SqlIdentifier name, @Nullable SqlNodeList columnList, SqlNode query) { super(OPERATOR, pos, replace, ifNotExists); this.name = Objects.requireNonNull(name); @@ -52,6 +54,7 @@ public class SqlCreateMaterializedView extends SqlCreate { this.query = Objects.requireNonNull(query); } + @SuppressWarnings("nullness") public List getOperandList() { return ImmutableNullableList.of(name, columnList, query); } diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java index 6e033180b6dd..886d6dc9c813 100644 --- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java +++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java @@ -27,6 +27,8 @@ import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.util.ImmutableNullableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import java.util.Objects; @@ -35,21 +37,22 @@ */ public class SqlCreateTable extends SqlCreate { public final SqlIdentifier name; - public final SqlNodeList columnList; - public final SqlNode query; + public final @Nullable SqlNodeList columnList; + public final @Nullable SqlNode query; private static final SqlOperator OPERATOR = new SqlSpecialOperator("CREATE TABLE", SqlKind.CREATE_TABLE); /** Creates a SqlCreateTable. */ protected SqlCreateTable(SqlParserPos pos, boolean replace, boolean ifNotExists, - SqlIdentifier name, SqlNodeList columnList, SqlNode query) { + SqlIdentifier name, @Nullable SqlNodeList columnList, @Nullable SqlNode query) { super(OPERATOR, pos, replace, ifNotExists); this.name = Objects.requireNonNull(name); this.columnList = columnList; // may be null this.query = query; // for "CREATE TABLE ... AS query"; may be null } + @SuppressWarnings("nullness") public List getOperandList() { return ImmutableNullableList.of(name, columnList, query); } diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateType.java b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateType.java index 40e06899481c..f12b57518862 100644 --- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateType.java +++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateType.java @@ -28,6 +28,8 @@ import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.util.ImmutableNullableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import java.util.Objects; @@ -36,21 +38,22 @@ */ public class SqlCreateType extends SqlCreate { public final SqlIdentifier name; - public final SqlNodeList attributeDefs; - public final SqlDataTypeSpec dataType; + public final @Nullable SqlNodeList attributeDefs; + public final @Nullable SqlDataTypeSpec dataType; private static final SqlOperator OPERATOR = new SqlSpecialOperator("CREATE TYPE", SqlKind.CREATE_TYPE); /** Creates a SqlCreateType. */ SqlCreateType(SqlParserPos pos, boolean replace, SqlIdentifier name, - SqlNodeList attributeDefs, SqlDataTypeSpec dataType) { + @Nullable SqlNodeList attributeDefs, @Nullable SqlDataTypeSpec dataType) { super(OPERATOR, pos, replace, false); this.name = Objects.requireNonNull(name); this.attributeDefs = attributeDefs; // may be null this.dataType = dataType; // may be null } + @SuppressWarnings("nullness") @Override public List getOperandList() { return ImmutableNullableList.of(name, attributeDefs); } diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateView.java b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateView.java index ab05ecf49199..542d8b35e98c 100644 --- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateView.java +++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlCreateView.java @@ -27,6 +27,8 @@ import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.util.ImmutableNullableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import java.util.Objects; @@ -35,7 +37,7 @@ */ public class SqlCreateView extends SqlCreate { public final SqlIdentifier name; - public final SqlNodeList columnList; + public final @Nullable SqlNodeList columnList; public final SqlNode query; private static final SqlOperator OPERATOR = @@ -43,13 +45,14 @@ public class SqlCreateView extends SqlCreate { /** Creates a SqlCreateView. */ SqlCreateView(SqlParserPos pos, boolean replace, SqlIdentifier name, - SqlNodeList columnList, SqlNode query) { + @Nullable SqlNodeList columnList, SqlNode query) { super(OPERATOR, pos, replace, false); this.name = Objects.requireNonNull(name); this.columnList = columnList; // may be null this.query = Objects.requireNonNull(query); } + @SuppressWarnings("nullness") public List getOperandList() { return ImmutableNullableList.of(name, columnList, query); } diff --git a/core/src/main/java/org/apache/calcite/sql/ddl/SqlKeyConstraint.java b/core/src/main/java/org/apache/calcite/sql/ddl/SqlKeyConstraint.java index 5a9f06c35865..bc526e1d1516 100644 --- a/core/src/main/java/org/apache/calcite/sql/ddl/SqlKeyConstraint.java +++ b/core/src/main/java/org/apache/calcite/sql/ddl/SqlKeyConstraint.java @@ -27,6 +27,8 @@ import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.util.ImmutableNullableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -41,11 +43,11 @@ public class SqlKeyConstraint extends SqlCall { protected static final SqlSpecialOperator PRIMARY = new SqlSpecialOperator("PRIMARY KEY", SqlKind.PRIMARY_KEY); - private final SqlIdentifier name; + private final @Nullable SqlIdentifier name; private final SqlNodeList columnList; /** Creates a SqlKeyConstraint. */ - SqlKeyConstraint(SqlParserPos pos, SqlIdentifier name, + SqlKeyConstraint(SqlParserPos pos, @Nullable SqlIdentifier name, SqlNodeList columnList) { super(pos); this.name = name; @@ -72,6 +74,7 @@ public static SqlKeyConstraint primary(SqlParserPos pos, SqlIdentifier name, return UNIQUE; } + @SuppressWarnings("nullness") @Override public List getOperandList() { return ImmutableNullableList.of(name, columnList); } diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/MssqlSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/MssqlSqlDialect.java index 2ec892cfec80..62326d395731 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/MssqlSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/MssqlSqlDialect.java @@ -120,8 +120,8 @@ public MssqlSqlDialect(Context context) { } } - @Override public void unparseTopN(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + @Override public void unparseTopN(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { if (top) { // Per Microsoft: // "For backward compatibility, the parentheses are optional in SELECT diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/SybaseSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/SybaseSqlDialect.java index 8cbf3ea85b3c..bc26d892696e 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/SybaseSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/SybaseSqlDialect.java @@ -20,6 +20,8 @@ import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlWriter; +import javax.annotation.Nullable; + /** * A SqlDialect implementation for the Sybase database. */ @@ -40,8 +42,8 @@ public SybaseSqlDialect(Context context) { // Sybase uses "SELECT TOP (n)" rather than "FETCH NEXT n ROWS". } - @Override public void unparseTopN(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + @Override public void unparseTopN(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { // Parentheses are not required, but we use them to be consistent with // Microsoft SQL Server, which recommends them but does not require them. // diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCase.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCase.java index 78c347e676a5..c6918bc1204e 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCase.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCase.java @@ -29,6 +29,7 @@ import java.util.List; + /** * A SqlCase is a node of a parse tree which represents a case * statement. It warrants its own node type just because we have a lot of @@ -38,7 +39,7 @@ public class SqlCase extends SqlCall { @Nullable SqlNode value; SqlNodeList whenList; SqlNodeList thenList; - SqlNode elseExpr; + @Nullable SqlNode elseExpr; //~ Constructors ----------------------------------------------------------- @@ -52,7 +53,7 @@ public class SqlCase extends SqlCall { * @param elseExpr The implicit or explicit ELSE expression */ public SqlCase(SqlParserPos pos, @Nullable SqlNode value, SqlNodeList whenList, - SqlNodeList thenList, SqlNode elseExpr) { + SqlNodeList thenList, @Nullable SqlNode elseExpr) { super(pos); this.value = value; this.whenList = whenList; @@ -70,8 +71,8 @@ public SqlCase(SqlParserPos pos, @Nullable SqlNode value, SqlNodeList whenList, * ELSE elseClause
    * END */ - public static SqlCase createSwitched(SqlParserPos pos, SqlNode value, - SqlNodeList whenList, SqlNodeList thenList, SqlNode elseClause) { + public static SqlCase createSwitched(SqlParserPos pos, @Nullable SqlNode value, + SqlNodeList whenList, SqlNodeList thenList, @Nullable SqlNode elseClause) { if (null != value) { List list = whenList.getList(); for (int i = 0; i < list.size(); i++) { @@ -107,6 +108,7 @@ public List getOperandList() { return UnmodifiableArrayList.of(value, whenList, thenList, elseExpr); } + @SuppressWarnings("assignment.type.incompatible") @Override public void setOperand(int i, @Nullable SqlNode operand) { switch (i) { case 0: @@ -138,7 +140,7 @@ public SqlNodeList getThenOperands() { return thenList; } - public SqlNode getElseOperand() { + public @Nullable SqlNode getElseOperand() { return elseExpr; } } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCaseOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCaseOperator.java index a8635be3edd5..84d32cf615f3 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCaseOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCaseOperator.java @@ -52,6 +52,7 @@ import java.util.ArrayList; import java.util.List; +import static org.apache.calcite.linq4j.Nullness.assertNonNull; import static org.apache.calcite.util.Static.RESOURCE; /** @@ -319,7 +320,9 @@ private RelDataType inferTypeFromOperands(SqlOperatorBinding opBinding) { } thenTypes.add(Iterables.getLast(argTypes)); - return typeFactory.leastRestrictive(thenTypes); + return assertNonNull( + typeFactory.leastRestrictive(thenTypes), + "Can't find leastRestrictive type for " + thenTypes); } public SqlOperandCountRange getOperandCountRange() { @@ -330,10 +333,11 @@ public SqlSyntax getSyntax() { return SqlSyntax.SPECIAL; } + @SuppressWarnings("argument.type.incompatible") public SqlCall createCall( @Nullable SqlLiteral functionQualifier, SqlParserPos pos, - SqlNode... operands) { + @Nullable SqlNode... operands) { assert functionQualifier == null; assert operands.length == 4; return new SqlCase(pos, operands[0], (SqlNodeList) operands[1], diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlGeoFunctions.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlGeoFunctions.java index 7638d4264244..4986f1f7af7f 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlGeoFunctions.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlGeoFunctions.java @@ -37,6 +37,8 @@ import com.esri.core.geometry.Geometry; import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.math.BigDecimal; /** @@ -128,7 +130,7 @@ public boolean isRolledUp(String column) { } public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, - SqlNode parent, CalciteConnectionConfig config) { + @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return false; } } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonArrayAggAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonArrayAggAggFunction.java index 962338773ea6..d06e907a0491 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonArrayAggAggFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonArrayAggAggFunction.java @@ -73,7 +73,7 @@ public SqlJsonArrayAggAggFunction(SqlKind kind, } @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { assert operands.length == 1 || operands.length == 2; final SqlNode valueExpr = operands[0]; if (operands.length == 2) { @@ -87,7 +87,8 @@ public SqlJsonArrayAggAggFunction(SqlKind kind, return createCall_(functionQualifier, pos, valueExpr); } - private SqlCall createCall_(SqlLiteral functionQualifier, SqlParserPos pos, SqlNode valueExpr) { + private SqlCall createCall_(@Nullable SqlLiteral functionQualifier, SqlParserPos pos, + @Nullable SqlNode valueExpr) { return super.createCall(functionQualifier, pos, valueExpr); } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonArrayFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonArrayFunction.java index 415414cf4d47..73031d6affac 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonArrayFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonArrayFunction.java @@ -56,7 +56,7 @@ public SqlJsonArrayFunction() { } @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { if (operands[0] == null) { operands[0] = SqlLiteral.createSymbol(SqlJsonConstructorNullClause.ABSENT_ON_NULL, diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonDepthFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonDepthFunction.java index 9335f94a2181..919c40a77cc3 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonDepthFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonDepthFunction.java @@ -56,7 +56,7 @@ public SqlJsonDepthFunction() { } @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { return super.createCall(functionQualifier, pos, operands); } } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonObjectFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonObjectFunction.java index 33d6c047db41..5696fd386a15 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonObjectFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonObjectFunction.java @@ -94,7 +94,7 @@ public SqlJsonObjectFunction() { } @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { if (operands[0] == null) { operands[0] = SqlLiteral.createSymbol( SqlJsonConstructorNullClause.NULL_ON_NULL, pos); diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonPrettyFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonPrettyFunction.java index fbb5293bfab5..8e6fc4b3f42c 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonPrettyFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonPrettyFunction.java @@ -54,7 +54,7 @@ public SqlJsonPrettyFunction() { } @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { return super.createCall(functionQualifier, pos, operands); } } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonQueryFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonQueryFunction.java index 6d5888b6bb01..5c5ba03b4e15 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonQueryFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonQueryFunction.java @@ -80,7 +80,7 @@ public SqlJsonQueryFunction() { } @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { if (operands[2] == null) { operands[2] = SqlLiteral.createSymbol(SqlJsonQueryWrapperBehavior.WITHOUT_ARRAY, pos); } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonTypeFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonTypeFunction.java index f8694c8a35e6..afa06cad3692 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonTypeFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonTypeFunction.java @@ -55,7 +55,7 @@ public SqlJsonTypeFunction() { } @Override public SqlCall createCall(@Nullable SqlLiteral functionQualifier, - SqlParserPos pos, SqlNode... operands) { + SqlParserPos pos, @Nullable SqlNode... operands) { return super.createCall(functionQualifier, pos, operands); } } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlPosixRegexOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlPosixRegexOperator.java index 449faf8a605c..c41fb9e2b086 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlPosixRegexOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlPosixRegexOperator.java @@ -83,7 +83,7 @@ public SqlOperandCountRange getOperandCountRange() { public SqlCall createCall( @Nullable SqlLiteral functionQualifier, SqlParserPos pos, - SqlNode... operands) { + @Nullable SqlNode... operands) { pos = pos.plusAll(Arrays.asList(operands)); operands = Arrays.copyOf(operands, operands.length + 1); operands[operands.length - 1] = SqlLiteral.createBoolean(caseSensitive, SqlParserPos.ZERO); diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlTrimFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlTrimFunction.java index 1d71dff5e1b2..380815738a23 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlTrimFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlTrimFunction.java @@ -123,7 +123,7 @@ public String getSignatureTemplate(final int operandsCount) { public SqlCall createCall( @Nullable SqlLiteral functionQualifier, SqlParserPos pos, - SqlNode... operands) { + @Nullable SqlNode... operands) { assert functionQualifier == null; switch (operands.length) { case 1: diff --git a/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java b/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java index 4350bdd6e9bb..ba6c8abe422b 100644 --- a/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java +++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlAbstractParserImpl.java @@ -34,6 +34,10 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; +import org.checkerframework.checker.initialization.qual.UnderInitialization; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.PolyNull; + import java.io.Reader; import java.io.StringReader; import java.lang.reflect.InvocationTargetException; @@ -349,7 +353,7 @@ protected enum ExprContext { protected int nDynamicParams; - protected String originalSql; + protected @Nullable String originalSql; protected final List warnings = new ArrayList<>(); @@ -420,7 +424,7 @@ protected SqlCall createCall( * @param ex dirty excn * @return clean excn */ - public abstract SqlParseException normalizeException(Throwable ex); + public abstract SqlParseException normalizeException(@PolyNull Throwable ex); protected abstract SqlParserPos getPos() throws Exception; @@ -498,7 +502,7 @@ public void setOriginalSql(String originalSql) { /** * Returns the SQL text. */ - public String getOriginalSql() { + public @Nullable String getOriginalSql() { return originalSql; } @@ -668,6 +672,7 @@ public MetadataImpl(SqlAbstractParserImpl sqlParser) { * Initializes lists of keywords. */ private void initList( + @UnderInitialization MetadataImpl this, SqlAbstractParserImpl parserImpl, Set keywords, String name) { @@ -713,13 +718,14 @@ private void initList( * @param name Name of method. For example "ReservedFunctionName". * @return Result of calling method */ - private Object virtualCall( + private @Nullable Object virtualCall( + @UnderInitialization MetadataImpl this, SqlAbstractParserImpl parserImpl, String name) throws Throwable { Class clazz = parserImpl.getClass(); try { - final Method method = clazz.getMethod(name, (Class[]) null); - return method.invoke(parserImpl, (Object[]) null); + final Method method = clazz.getMethod(name); + return method.invoke(parserImpl); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); throw parserImpl.normalizeException(cause); @@ -729,7 +735,8 @@ private Object virtualCall( /** * Builds a comma-separated list of JDBC reserved words. */ - private String constructSql92ReservedWordList() { + private String constructSql92ReservedWordList( + @UnderInitialization MetadataImpl this) { StringBuilder sb = new StringBuilder(); TreeSet jdbcReservedSet = new TreeSet<>(); jdbcReservedSet.addAll(tokenSet); diff --git a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserPos.java b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserPos.java index 27e9c37fe0f5..fb0091d0c91a 100644 --- a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserPos.java +++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserPos.java @@ -22,6 +22,7 @@ import com.google.common.collect.Lists; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.PolyNull; import java.io.Serializable; import java.util.AbstractList; @@ -30,7 +31,6 @@ import java.util.List; import java.util.Objects; -import static org.apache.calcite.linq4j.Nullness.assertNonNull; import static org.apache.calcite.util.Static.RESOURCE; /** @@ -170,7 +170,7 @@ public SqlParserPos plusAll(SqlNode[] nodes) { /** * Combines this parser position with a list of positions. */ - public SqlParserPos plusAll(Collection nodeList) { + public SqlParserPos plusAll(Collection<@Nullable SqlNode> nodeList) { int line = getLineNum(); int column = getColumnNum(); int endLine = getEndLineNum(); @@ -197,11 +197,11 @@ public int size() { }; } - private static Iterable toPos(Iterable nodes) { + private static Iterable<@PolyNull SqlParserPos> toPos(Iterable<@PolyNull SqlNode> nodes) { return Iterables.transform(nodes, node -> { if (node == null) { // Nulls are not expected - return assertNonNull(null); + return null; } else { return node.getParserPosition(); } @@ -266,7 +266,7 @@ public int size() { * @return Sum of parser positions */ private static SqlParserPos sum( - Iterable poses, + Iterable poses, int line, int column, int endLine, diff --git a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java index 2545c69ed730..9fba8f9ba51c 100644 --- a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java +++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java @@ -47,6 +47,7 @@ import com.google.common.base.Preconditions; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; import org.slf4j.Logger; @@ -82,7 +83,7 @@ private SqlParserUtil() { /** Returns the character-set prefix of a SQL string literal; returns null if * there is none. */ - public static String getCharacterSet(String s) { + public static @Nullable String getCharacterSet(String s) { if (s.charAt(0) == '\'') { return null; } @@ -526,7 +527,7 @@ public static String addCarets( return sqlWithCarets; } - public static String getTokenVal(String token) { + public static @Nullable String getTokenVal(String token) { // We don't care about the token which are not string if (!token.startsWith("\"")) { return null; @@ -972,7 +973,7 @@ public void replaceSublist(int start, int end, SqlNode e) { /** Pre-initialized {@link DateFormat} objects, to be used within the current * thread, because {@code DateFormat} is not thread-safe. */ private static class Format { - private static final ThreadLocal PER_THREAD = + private static final ThreadLocal<@Nullable Format> PER_THREAD = ThreadLocal.withInitial(Format::new); final DateFormat timestamp = new SimpleDateFormat(DateTimeUtils.TIMESTAMP_FORMAT_STRING, diff --git a/core/src/main/java/org/apache/calcite/sql/pretty/SqlPrettyWriter.java b/core/src/main/java/org/apache/calcite/sql/pretty/SqlPrettyWriter.java index 9b1516f74e0e..52a7f4fc058d 100644 --- a/core/src/main/java/org/apache/calcite/sql/pretty/SqlPrettyWriter.java +++ b/core/src/main/java/org/apache/calcite/sql/pretty/SqlPrettyWriter.java @@ -840,7 +840,7 @@ private SqlWriterConfig.LineFolding f3(SqlWriterConfig.@Nullable LineFolding fol */ protected Frame startList( FrameType frameType, - String keyword, + @Nullable String keyword, String open, String close) { assert frameType != null; @@ -866,7 +866,7 @@ protected Frame startList( return frame; } - public void endList(Frame frame) { + public void endList(@Nullable Frame frame) { FrameImpl endedFrame = (FrameImpl) frame; Preconditions.checkArgument(frame == this.frame, "Frame does not match current frame"); @@ -956,7 +956,7 @@ private static boolean needWhitespaceAfter(String s) { protected void whiteSpace() { if (needWhitespace) { - if (nextWhitespace.equals(NL)) { + if (NL.equals(nextWhitespace)) { newlineAndIndent(); } else { buf.append(nextWhitespace); @@ -1015,14 +1015,14 @@ public void identifier(String name, boolean quoted) { setNeedWhitespace(true); } - public void fetchOffset(SqlNode fetch, SqlNode offset) { + public void fetchOffset(@Nullable SqlNode fetch, @Nullable SqlNode offset) { if (fetch == null && offset == null) { return; } dialect.unparseOffsetFetch(this, offset, fetch); } - public void topN(SqlNode fetch, SqlNode offset) { + public void topN(@Nullable SqlNode fetch, @Nullable SqlNode offset) { if (fetch == null && offset == null) { return; } diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeCoercionRule.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeCoercionRule.java index fc785d906311..032eb9758b7e 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeCoercionRule.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeCoercionRule.java @@ -19,6 +19,8 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -72,7 +74,7 @@ public class SqlTypeCoercionRule implements SqlTypeMappingRule { private static final SqlTypeCoercionRule INSTANCE; - public static final ThreadLocal THREAD_PROVIDERS = + public static final ThreadLocal<@Nullable SqlTypeCoercionRule> THREAD_PROVIDERS = ThreadLocal.withInitial(() -> SqlTypeCoercionRule.INSTANCE); //~ Instance fields -------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeMappingRules.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeMappingRules.java index 35eccc0d05a8..93c786bbde98 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeMappingRules.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeMappingRules.java @@ -16,7 +16,6 @@ */ package org.apache.calcite.sql.type; -import org.apache.calcite.linq4j.Nullness; import org.apache.calcite.util.Util; import com.google.common.cache.CacheBuilder; diff --git a/core/src/main/java/org/apache/calcite/sql/util/SqlString.java b/core/src/main/java/org/apache/calcite/sql/util/SqlString.java index a7d9c324befd..c1678f5cc565 100644 --- a/core/src/main/java/org/apache/calcite/sql/util/SqlString.java +++ b/core/src/main/java/org/apache/calcite/sql/util/SqlString.java @@ -51,7 +51,8 @@ public SqlString(SqlDialect dialect, String sql) { * @param sql text * @param dynamicParameters indices */ - public SqlString(SqlDialect dialect, String sql, ImmutableList dynamicParameters) { + public SqlString(SqlDialect dialect, String sql, + @Nullable ImmutableList dynamicParameters) { this.dialect = dialect; this.sql = sql; this.dynamicParameters = dynamicParameters; diff --git a/core/src/main/java/org/apache/calcite/sql/validate/AbstractNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/AbstractNamespace.java index aa13ddf02ae4..cb937799aace 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/AbstractNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/AbstractNamespace.java @@ -48,12 +48,12 @@ abstract class AbstractNamespace implements SqlValidatorNamespace { * Type of the output row, which comprises the name and type of each output * column. Set on validate. */ - protected RelDataType rowType; + protected @Nullable RelDataType rowType; /** As {@link #rowType}, but not necessarily a struct. */ - protected RelDataType type; + protected @Nullable RelDataType type; - protected final SqlNode enclosingNode; + protected final @Nullable SqlNode enclosingNode; //~ Constructors ----------------------------------------------------------- @@ -65,7 +65,7 @@ abstract class AbstractNamespace implements SqlValidatorNamespace { */ AbstractNamespace( SqlValidatorImpl validator, - SqlNode enclosingNode) { + @Nullable SqlNode enclosingNode) { this.validator = validator; this.enclosingNode = enclosingNode; } @@ -134,7 +134,7 @@ public void setType(RelDataType type) { this.rowType = convertToStruct(type); } - public SqlNode getEnclosingNode() { + public @Nullable SqlNode getEnclosingNode() { return enclosingNode; } @@ -142,7 +142,7 @@ public SqlNode getEnclosingNode() { return null; } - public SqlValidatorNamespace lookupChild(String name) { + public @Nullable SqlValidatorNamespace lookupChild(String name) { return validator.lookupFieldNamespace( getRowType(), name); diff --git a/core/src/main/java/org/apache/calcite/sql/validate/AggFinder.java b/core/src/main/java/org/apache/calcite/sql/validate/AggFinder.java index 4dc9fabe7a6e..b0adc20a5969 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/AggFinder.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/AggFinder.java @@ -21,6 +21,8 @@ import org.apache.calcite.sql.SqlOperatorTable; import org.apache.calcite.util.Util; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -54,7 +56,7 @@ class AggFinder extends AggVisitor { * @param node Parse tree to search * @return First aggregate function in parse tree, or null if not found */ - public SqlCall findAgg(SqlNode node) { + public @Nullable SqlCall findAgg(SqlNode node) { try { node.accept(this); return null; @@ -64,7 +66,7 @@ public SqlCall findAgg(SqlNode node) { } } - public SqlCall findAgg(List nodes) { + public @Nullable SqlCall findAgg(List nodes) { try { for (SqlNode node : nodes) { node.accept(this); diff --git a/core/src/main/java/org/apache/calcite/sql/validate/AliasNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/AliasNamespace.java index 4abd72edbf82..4e8ae2c8e4e2 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/AliasNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/AliasNamespace.java @@ -27,6 +27,8 @@ import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.util.Util; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.List; @@ -121,7 +123,7 @@ private String getString(RelDataType rowType) { return buf.toString(); } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return call; } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/CollectNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/CollectNamespace.java index 1d48e87862b3..efc5a5b56307 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/CollectNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/CollectNamespace.java @@ -21,6 +21,8 @@ import org.apache.calcite.sql.SqlKind; import org.apache.calcite.sql.SqlNode; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Namespace for COLLECT and TABLE constructs. * @@ -68,7 +70,7 @@ protected RelDataType validateImpl(RelDataType targetRowType) { return child.getOperator().deriveType(validator, scope, child); } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return child; } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/CollectScope.java b/core/src/main/java/org/apache/calcite/sql/validate/CollectScope.java index 6dc60edaf95c..9d84f330cfe6 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/CollectScope.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/CollectScope.java @@ -19,6 +19,8 @@ import org.apache.calcite.sql.SqlCall; import org.apache.calcite.sql.SqlNode; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * The name-resolution context for expression inside a multiset call. The * objects visible are multiset expressions, and those inherited from the parent @@ -29,14 +31,14 @@ class CollectScope extends ListScope { //~ Instance fields -------------------------------------------------------- - private final SqlValidatorScope usingScope; + private final @Nullable SqlValidatorScope usingScope; private final SqlCall child; //~ Constructors ----------------------------------------------------------- CollectScope( SqlValidatorScope parent, - SqlValidatorScope usingScope, + @Nullable SqlValidatorScope usingScope, SqlCall child) { super(parent); this.usingScope = usingScope; diff --git a/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java index 64b450471493..b42049b8ee17 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/DelegatingNamespace.java @@ -74,15 +74,15 @@ public void validate(RelDataType targetRowType) { namespace.validate(targetRowType); } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return namespace.getNode(); } - public SqlNode getEnclosingNode() { + public @Nullable SqlNode getEnclosingNode() { return namespace.getEnclosingNode(); } - public SqlValidatorNamespace lookupChild( + public @Nullable SqlValidatorNamespace lookupChild( String name) { return namespace.lookupChild(name); } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/DelegatingScope.java b/core/src/main/java/org/apache/calcite/sql/validate/DelegatingScope.java index a630a9265077..3b26ed8f0cef 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/DelegatingScope.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/DelegatingScope.java @@ -35,6 +35,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -194,7 +196,7 @@ public RelDataType nullifyType(SqlNode node, RelDataType type) { } @SuppressWarnings("deprecation") - public SqlValidatorNamespace getTableNamespace(List names) { + public @Nullable SqlValidatorNamespace getTableNamespace(List names) { return parent.getTableNamespace(names); } @@ -530,7 +532,7 @@ public void validateExpr(SqlNode expr) { // be valid in the parent scope. } - public SqlWindow lookupWindow(String name) { + public @Nullable SqlWindow lookupWindow(String name) { return parent.lookupWindow(name); } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/EmptyScope.java b/core/src/main/java/org/apache/calcite/sql/validate/EmptyScope.java index 42636d54aa6b..d8365669e9ba 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/EmptyScope.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/EmptyScope.java @@ -38,6 +38,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -82,7 +84,7 @@ public void resolve(List names, SqlNameMatcher nameMatcher, } @SuppressWarnings("deprecation") - public SqlValidatorNamespace getTableNamespace(List names) { + public @Nullable SqlValidatorNamespace getTableNamespace(List names) { SqlValidatorTable table = validator.catalogReader.getTable(names); return table != null ? new TableNamespace(validator, table) @@ -215,7 +217,7 @@ public void addChild(SqlValidatorNamespace ns, String alias, throw new UnsupportedOperationException(); } - public SqlWindow lookupWindow(String name) { + public @Nullable SqlWindow lookupWindow(String name) { // No windows defined in this scope. return null; } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/FieldNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/FieldNamespace.java index 74c87de59c63..79505ae2e061 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/FieldNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/FieldNamespace.java @@ -19,6 +19,8 @@ import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.sql.SqlNode; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Implementation of {@link SqlValidatorNamespace} for a field of a record. * @@ -53,11 +55,11 @@ protected RelDataType validateImpl(RelDataType targetRowType) { return rowType; } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return null; } - public SqlValidatorNamespace lookupChild(String name) { + public @Nullable SqlValidatorNamespace lookupChild(String name) { if (rowType.isStruct()) { return validator.lookupFieldNamespace( rowType, diff --git a/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java index 45a4d88c13c7..6edf19a1702e 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/IdentifierNamespace.java @@ -45,7 +45,7 @@ public class IdentifierNamespace extends AbstractNamespace { //~ Instance fields -------------------------------------------------------- private final SqlIdentifier id; - private final SqlValidatorScope parentScope; + private final @Nullable SqlValidatorScope parentScope; public final @Nullable SqlNodeList extendList; /** @@ -71,8 +71,8 @@ public class IdentifierNamespace extends AbstractNamespace { * @param parentScope Parent scope which this namespace turns to in order to */ IdentifierNamespace(SqlValidatorImpl validator, SqlIdentifier id, - @Nullable SqlNodeList extendList, SqlNode enclosingNode, - SqlValidatorScope parentScope) { + @Nullable SqlNodeList extendList, @Nullable SqlNode enclosingNode, + @Nullable SqlValidatorScope parentScope) { super(validator, enclosingNode); this.id = id; this.extendList = extendList; @@ -80,7 +80,7 @@ public class IdentifierNamespace extends AbstractNamespace { } IdentifierNamespace(SqlValidatorImpl validator, SqlNode node, - SqlNode enclosingNode, SqlValidatorScope parentScope) { + @Nullable SqlNode enclosingNode, @Nullable SqlValidatorScope parentScope) { this(validator, split(node).left, split(node).right, enclosingNode, parentScope); } @@ -247,7 +247,7 @@ public SqlIdentifier getId() { return id; } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return id; } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java index 2197a40e7703..8716aa587dd3 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/JoinNamespace.java @@ -21,6 +21,8 @@ import org.apache.calcite.sql.SqlJoin; import org.apache.calcite.sql.SqlNode; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Namespace representing the row type produced by joining two relations. */ @@ -59,7 +61,7 @@ protected RelDataType validateImpl(RelDataType targetRowType) { return typeFactory.createJoinType(leftType, rightType); } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return join; } } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java b/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java index 406ffb2c97ae..41c04142a98e 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/JoinScope.java @@ -20,6 +20,8 @@ import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlWindow; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * The name-resolution context for expression inside a JOIN clause. The objects * visible are the joined table expressions, and those inherited from the parent @@ -32,7 +34,7 @@ public class JoinScope extends ListScope { //~ Instance fields -------------------------------------------------------- - private final SqlValidatorScope usingScope; + private final @Nullable SqlValidatorScope usingScope; private final SqlJoin join; //~ Constructors ----------------------------------------------------------- @@ -46,7 +48,7 @@ public class JoinScope extends ListScope { */ JoinScope( SqlValidatorScope parent, - SqlValidatorScope usingScope, + @Nullable SqlValidatorScope usingScope, SqlJoin join) { super(parent); this.usingScope = usingScope; @@ -77,7 +79,7 @@ public void addChild(SqlValidatorNamespace ns, String alias, } } - public SqlWindow lookupWindow(String name) { + public @Nullable SqlWindow lookupWindow(String name) { // Lookup window in enclosing select. if (usingScope != null) { return usingScope.lookupWindow(name); @@ -89,7 +91,7 @@ public SqlWindow lookupWindow(String name) { /** * Returns the scope which is used for resolving USING clause. */ - public SqlValidatorScope getUsingScope() { + public @Nullable SqlValidatorScope getUsingScope() { return usingScope; } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/MatchRecognizeNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/MatchRecognizeNamespace.java index d1ac797436d2..06a74c86d343 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/MatchRecognizeNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/MatchRecognizeNamespace.java @@ -20,6 +20,8 @@ import org.apache.calcite.sql.SqlMatchRecognize; import org.apache.calcite.sql.SqlNode; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Namespace for a {@code MATCH_RECOGNIZE} clause. */ @@ -39,7 +41,7 @@ protected MatchRecognizeNamespace(SqlValidatorImpl validator, return rowType; } - @Override public SqlMatchRecognize getNode() { + @Override public @Nullable SqlNode getNode() { return matchRecognize; } } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/ParameterNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/ParameterNamespace.java index de21ac843f63..aecf23fcec4e 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/ParameterNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/ParameterNamespace.java @@ -19,6 +19,8 @@ import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.sql.SqlNode; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Namespace representing the type of a dynamic parameter. * @@ -38,7 +40,7 @@ class ParameterNamespace extends AbstractNamespace { //~ Methods ---------------------------------------------------------------- - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return null; } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/ProcedureNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/ProcedureNamespace.java index c4ffb6de14ff..c378696a410c 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/ProcedureNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/ProcedureNamespace.java @@ -25,6 +25,8 @@ import org.apache.calcite.sql.type.SqlReturnTypeInference; import org.apache.calcite.sql.type.SqlTypeName; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Namespace whose contents are defined by the result of a call to a * user-defined procedure. @@ -70,7 +72,7 @@ public RelDataType validateImpl(RelDataType targetRowType) { return rowTypeInference.inferReturnType(callBinding); } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return call; } } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SchemaNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/SchemaNamespace.java index a73ee4947719..1ca962e0c1db 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SchemaNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SchemaNamespace.java @@ -23,6 +23,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import java.util.Objects; @@ -52,7 +54,7 @@ protected RelDataType validateImpl(RelDataType targetRowType) { return builder.build(); } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return null; } } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SelectNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/SelectNamespace.java index 5f05946f9d4a..75102b694edb 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SelectNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SelectNamespace.java @@ -21,6 +21,8 @@ import org.apache.calcite.sql.SqlSelect; import org.apache.calcite.sql.type.SqlTypeUtil; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Namespace offered by a sub-query. * @@ -52,7 +54,7 @@ public SelectNamespace( //~ Methods ---------------------------------------------------------------- // implement SqlValidatorNamespace, overriding return type - @Override public SqlSelect getNode() { + @Override public @Nullable SqlNode getNode() { return select; } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SelectScope.java b/core/src/main/java/org/apache/calcite/sql/validate/SelectScope.java index 2649d59e9187..a97142eff9c2 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SelectScope.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SelectScope.java @@ -27,6 +27,8 @@ import org.apache.calcite.util.Litmus; import org.apache.calcite.util.Pair; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.List; @@ -91,13 +93,13 @@ public class SelectScope extends ListScope { private final SqlSelect select; protected final List windowNames = new ArrayList<>(); - private List expandedSelectList = null; + private @Nullable List expandedSelectList = null; /** * List of column names which sort this scope. Empty if this scope is not * sorted. Null if has not been computed yet. */ - private SqlNodeList orderList; + private @Nullable SqlNodeList orderList; /** Scope to use to resolve windows. */ private final SqlValidatorScope windowParent; @@ -122,7 +124,7 @@ public class SelectScope extends ListScope { //~ Methods ---------------------------------------------------------------- - public SqlValidatorTable getTable() { + public @Nullable SqlValidatorTable getTable() { return null; } @@ -130,7 +132,7 @@ public SqlSelect getNode() { return select; } - public SqlWindow lookupWindow(String name) { + public @Nullable SqlWindow lookupWindow(String name) { final SqlNodeList windowList = select.getWindowList(); for (int i = 0; i < windowList.size(); i++) { SqlWindow window = (SqlWindow) windowList.get(i); @@ -214,11 +216,11 @@ public boolean existingWindowName(String winName) { return false; } - public List getExpandedSelectList() { + public @Nullable List getExpandedSelectList() { return expandedSelectList; } - public void setExpandedSelectList(List selectList) { + public void setExpandedSelectList(@Nullable List selectList) { expandedSelectList = selectList; } } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SetopNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/SetopNamespace.java index cb444b789d49..0b423d8e2830 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SetopNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SetopNamespace.java @@ -21,6 +21,8 @@ import org.apache.calcite.sql.SqlKind; import org.apache.calcite.sql.SqlNode; +import org.checkerframework.checker.nullness.qual.Nullable; + import static org.apache.calcite.util.Static.RESOURCE; /** @@ -50,7 +52,7 @@ protected SetopNamespace( //~ Methods ---------------------------------------------------------------- - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return call; } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java index b81d1fbe1dd9..ec946d60da36 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidator.java @@ -536,7 +536,7 @@ void setValidatedNodeType( * @param select SELECT statement * @return naming scope for SELECT statement, sans any aggregating scope */ - SelectScope getRawSelectScope(SqlSelect select); + @Nullable SelectScope getRawSelectScope(SqlSelect select); /** * Returns a scope containing the objects visible from the FROM clause of a @@ -636,7 +636,7 @@ RelDataType deriveConstructorType( SqlValidatorScope scope, SqlCall call, SqlFunction unresolvedConstructor, - SqlFunction resolvedConstructor, + @Nullable SqlFunction resolvedConstructor, List argTypes); /** diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java index 8251a6f730f8..057d83363a78 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java @@ -138,6 +138,7 @@ import java.util.stream.Collectors; import javax.annotation.Nonnull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; import static org.apache.calcite.sql.SqlUtil.stripAs; import static org.apache.calcite.util.Static.RESOURCE; @@ -192,7 +193,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints { /** * The name-resolution scope of a LATERAL TABLE clause. */ - private TableScope tableScope = null; + private @Nullable TableScope tableScope = null; /** * Maps a {@link SqlNode node} to the @@ -1088,7 +1089,7 @@ public SqlValidatorScope getSelectScope(SqlSelect select) { return clauseScopes.get(IdPair.of(select, Clause.SELECT)); } - public SelectScope getRawSelectScope(SqlSelect select) { + public @Nullable SelectScope getRawSelectScope(SqlSelect select) { SqlValidatorScope scope = getSelectScope(select); if (scope instanceof AggregatingSelectScope) { scope = ((AggregatingSelectScope) scope).getParent(); @@ -1126,7 +1127,7 @@ public SqlValidatorScope getOverScope(SqlNode node) { return scopes.get(node); } - private SqlValidatorNamespace getNamespace(SqlNode node, + private @Nullable SqlValidatorNamespace getNamespace(SqlNode node, SqlValidatorScope scope) { if (node instanceof SqlIdentifier && scope instanceof DelegatingScope) { final SqlIdentifier id = (SqlIdentifier) node; @@ -1193,7 +1194,7 @@ private SqlValidatorNamespace getNamespace(SqlIdentifier id, DelegatingScope sco } } - private void handleOffsetFetch(SqlNode offset, SqlNode fetch) { + private void handleOffsetFetch(@Nullable SqlNode offset, @Nullable SqlNode fetch) { if (offset instanceof SqlDynamicParam) { setValidatedNodeType(offset, typeFactory.createSqlType(SqlTypeName.INTEGER)); @@ -1214,7 +1215,7 @@ private void handleOffsetFetch(SqlNode offset, SqlNode fetch) { * @return rewritten expression */ protected @Nullable SqlNode performUnconditionalRewrites( - SqlNode node, + @Nullable SqlNode node, boolean underFrom) { if (node == null) { return null; @@ -1623,7 +1624,7 @@ protected SqlSelect createSourceSelectForDelete(SqlDelete call) { * Returns null if there is no common type. E.g. if the rows have a * different number of columns. */ - RelDataType getTableConstructorRowType( + @Nullable RelDataType getTableConstructorRowType( SqlCall values, SqlValidatorScope scope) { final List rows = values.getOperandList(); @@ -1762,7 +1763,7 @@ public RelDataType deriveConstructorType( SqlValidatorScope scope, SqlCall call, SqlFunction unresolvedConstructor, - SqlFunction resolvedConstructor, + @Nullable SqlFunction resolvedConstructor, List argTypes) { SqlIdentifier sqlIdentifier = unresolvedConstructor.getSqlIdentifier(); assert sqlIdentifier != null; @@ -1985,7 +1986,7 @@ private void registerMatchRecognize( SqlValidatorScope usingScope, SqlMatchRecognize call, SqlNode enclosingNode, - String alias, + @Nullable String alias, boolean forceNullable) { final MatchRecognizeNamespace matchRecognizeNamespace = @@ -2023,12 +2024,14 @@ protected MatchRecognizeNamespace createMatchRecognizeNameSpace( * @param forceNullable Whether to force the type of namespace to be nullable */ protected void registerNamespace( - SqlValidatorScope usingScope, - String alias, + @Nullable SqlValidatorScope usingScope, + @Nullable String alias, SqlValidatorNamespace ns, boolean forceNullable) { namespaces.put(ns.getNode(), ns); if (usingScope != null) { + assert alias != null : "Registering namespace " + ns + ", into scope " + usingScope + + ", so alias must not be null"; usingScope.addChild(ns, alias, forceNullable); } } @@ -2070,8 +2073,8 @@ private SqlNode registerFrom( boolean register, final SqlNode node, SqlNode enclosingNode, - String alias, - SqlNodeList extendList, + @Nullable String alias, + @Nullable SqlNodeList extendList, boolean forceNullable, final boolean lateral) { final SqlKind kind = node.getKind(); @@ -2141,7 +2144,7 @@ private SqlNode registerFrom( case AS: call = (SqlCall) node; if (alias == null) { - alias = call.operand(1).toString(); + alias = String.valueOf(call.operand(1)); } final boolean needAlias = call.operandCount() > 2; expr = call.operand(0); @@ -2464,10 +2467,10 @@ protected SetopNamespace createSetopNamespace( */ private void registerQuery( SqlValidatorScope parentScope, - SqlValidatorScope usingScope, + @Nullable SqlValidatorScope usingScope, SqlNode node, SqlNode enclosingNode, - String alias, + @Nullable String alias, boolean forceNullable) { Preconditions.checkArgument(usingScope == null || alias != null); registerQuery( @@ -2494,10 +2497,10 @@ private void registerQuery( */ private void registerQuery( SqlValidatorScope parentScope, - SqlValidatorScope usingScope, + @Nullable SqlValidatorScope usingScope, SqlNode node, SqlNode enclosingNode, - String alias, + @Nullable String alias, boolean forceNullable, boolean checkUpdate) { Objects.requireNonNull(node); @@ -2809,10 +2812,10 @@ private void registerQuery( private void registerSetop( SqlValidatorScope parentScope, - SqlValidatorScope usingScope, + @Nullable SqlValidatorScope usingScope, SqlNode node, SqlNode enclosingNode, - String alias, + @Nullable String alias, boolean forceNullable) { SqlCall call = (SqlCall) node; final SetopNamespace setopNamespace = @@ -2834,10 +2837,10 @@ private void registerSetop( private void registerWith( SqlValidatorScope parentScope, - SqlValidatorScope usingScope, + @Nullable SqlValidatorScope usingScope, SqlWith with, SqlNode enclosingNode, - String alias, + @Nullable String alias, boolean forceNullable, boolean checkUpdate) { final WithNamespace withNamespace = @@ -2896,7 +2899,7 @@ protected boolean isOverAggregateWindow(SqlNode node) { * *

    The node is useful context for error messages, * but you cannot assume that the node is the only aggregate function. */ - protected SqlNode getAggregate(SqlSelect select) { + protected @Nullable SqlNode getAggregate(SqlSelect select) { SqlNode node = select.getGroup(); if (node != null) { return node; @@ -2910,7 +2913,7 @@ protected SqlNode getAggregate(SqlSelect select) { /** If there is at least one call to an aggregate function, returns the * first. */ - private SqlNode getAgg(SqlSelect select) { + private @Nullable SqlNode getAgg(SqlSelect select) { final SelectScope selectScope = getRawSelectScope(select); if (selectScope != null) { final List selectList = selectScope.getExpandedSelectList(); @@ -2936,7 +2939,7 @@ private void validateNodeFeature(SqlNode node) { private void registerSubQueries( SqlValidatorScope parentScope, - SqlNode node) { + @Nullable SqlNode node) { if (node == null) { return; } @@ -3478,7 +3481,7 @@ private void checkRollUpInOrderBy(SqlSelect select) { } } - private void checkRollUpInWindow(SqlWindow window, SqlValidatorScope scope) { + private void checkRollUpInWindow(@Nullable SqlWindow window, SqlValidatorScope scope) { if (window != null) { for (SqlNode node : window.getPartitionList()) { checkRollUp(null, window, node, scope, "PARTITION BY"); @@ -3496,14 +3499,14 @@ private void checkRollUpInWindowDecl(SqlSelect select) { } } - private SqlNode stripDot(SqlNode node) { + private @Nullable SqlNode stripDot(@Nullable SqlNode node) { if (node != null && node.getKind() == SqlKind.DOT) { return stripDot(((SqlCall) node).operand(0)); } return node; } - private void checkRollUp(SqlNode grandParent, SqlNode parent, + private void checkRollUp(@Nullable SqlNode grandParent, @Nullable SqlNode parent, SqlNode current, SqlValidatorScope scope, @Nullable String optionalClause) { current = stripAs(current); if (current instanceof SqlCall && !(current instanceof SqlSelect)) { @@ -3511,7 +3514,7 @@ private void checkRollUp(SqlNode grandParent, SqlNode parent, checkRollUpInWindow(getWindowInOver(current), scope); current = stripOver(current); - List children = ((SqlCall) stripAs(stripDot(current))).getOperandList(); + List<@Nullable SqlNode> children = ((SqlCall) stripAs(stripDot(current))).getOperandList(); for (SqlNode child : children) { checkRollUp(parent, current, child, scope, optionalClause); } @@ -3572,7 +3575,7 @@ private static SqlNode stripOver(SqlNode node) { // Returns true iff the given column is valid inside the given aggCall. private boolean isRolledUpColumnAllowedInAgg(SqlIdentifier identifier, SqlValidatorScope scope, - SqlCall aggCall, SqlNode parent) { + SqlCall aggCall, @Nullable SqlNode parent) { Pair pair = findTableColumnPair(identifier, scope); if (pair == null) { @@ -3611,7 +3614,7 @@ private boolean isRolledUpColumn(SqlIdentifier identifier, SqlValidatorScope sco return false; } - private boolean shouldCheckForRollUp(SqlNode from) { + private boolean shouldCheckForRollUp(@Nullable SqlNode from) { if (from != null) { SqlKind kind = stripAs(from).getKind(); return kind != SqlKind.VALUES && kind != SqlKind.SELECT; @@ -4286,7 +4289,7 @@ private void handleScalarSubQuery( */ protected RelDataType createTargetRowType( SqlValidatorTable table, - SqlNodeList targetColumnList, + @Nullable SqlNodeList targetColumnList, boolean append) { RelDataType baseRowType = table.getRowType(); if (targetColumnList == null) { @@ -4737,9 +4740,11 @@ public void validateDelete(SqlDelete call) { public void validateUpdate(SqlUpdate call) { final SqlValidatorNamespace targetNamespace = getNamespace(call); + assert targetNamespace != null : "targetNamespace was not found for call " + call; validateNamespace(targetNamespace, unknownType); final RelOptTable relOptTable = SqlValidatorUtil.getRelOptTable( - targetNamespace, catalogReader.unwrap(Prepare.CatalogReader.class), null, null); + targetNamespace, castNonNull(catalogReader.unwrap(Prepare.CatalogReader.class)), + null, null); final SqlValidatorTable table = relOptTable == null ? targetNamespace.getTable() : relOptTable.unwrap(SqlValidatorTable.class); @@ -5651,7 +5656,7 @@ private static class InsertNamespace extends DmlNamespace { this.node = Objects.requireNonNull(node); } - public SqlInsert getNode() { + public @Nullable SqlNode getNode() { return node; } } @@ -5668,7 +5673,7 @@ private static class UpdateNamespace extends DmlNamespace { this.node = Objects.requireNonNull(node); } - public SqlUpdate getNode() { + public @Nullable SqlNode getNode() { return node; } } @@ -5685,7 +5690,7 @@ private static class DeleteNamespace extends DmlNamespace { this.node = Objects.requireNonNull(node); } - public SqlDelete getNode() { + public @Nullable SqlNode getNode() { return node; } } @@ -5702,7 +5707,7 @@ private static class MergeNamespace extends DmlNamespace { this.node = Objects.requireNonNull(node); } - public SqlMerge getNode() { + public @Nullable SqlNode getNode() { return node; } } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java index 7aac98265057..57a76d7ff3ec 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorNamespace.java @@ -118,14 +118,14 @@ public interface SqlValidatorNamespace { * * @return parse tree node; null for {@link TableNamespace} */ - SqlNode getNode(); + @Nullable SqlNode getNode(); /** * Returns the parse tree node that at is at the root of this namespace and * includes all decorations. If there are no decorations, returns the same * as {@link #getNode()}. */ - SqlNode getEnclosingNode(); + @Nullable SqlNode getEnclosingNode(); /** * Looks up a child namespace of a given name. @@ -137,7 +137,7 @@ public interface SqlValidatorNamespace { * @param name Name of namespace * @return Namespace */ - SqlValidatorNamespace lookupChild(String name); + @Nullable SqlValidatorNamespace lookupChild(String name); /** * Returns whether this namespace has a field of a given name. diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorScope.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorScope.java index 8120617cbb85..0009337ae48b 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorScope.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorScope.java @@ -135,7 +135,7 @@ Map findQualifyingTableNames(String columnName, /** * Finds a window with a given name. Returns null if not found. */ - SqlWindow lookupWindow(String name); + @Nullable SqlWindow lookupWindow(String name); /** * Returns whether an expression is monotonic in this scope. For example, if @@ -184,7 +184,7 @@ Map findQualifyingTableNames(String columnName, /** @deprecated Use * {@link #resolveTable(List, SqlNameMatcher, Path, Resolved)}. */ @Deprecated // to be removed before 2.0 - SqlValidatorNamespace getTableNamespace(List names); + @Nullable SqlValidatorNamespace getTableNamespace(List names); /** * Looks up a table in this scope from its name. If found, calls @@ -215,7 +215,7 @@ default boolean isWithin(SqlValidatorScope scope2) { /** Callback from {@link SqlValidatorScope#resolve}. */ interface Resolved { void found(SqlValidatorNamespace namespace, boolean nullable, - SqlValidatorScope scope, Path path, List remainingNames); + @Nullable SqlValidatorScope scope, Path path, @Nullable List remainingNames); int count(); } @@ -292,7 +292,7 @@ class ResolvedImpl implements Resolved { final List resolves = new ArrayList<>(); public void found(SqlValidatorNamespace namespace, boolean nullable, - SqlValidatorScope scope, Path path, List remainingNames) { + @Nullable SqlValidatorScope scope, Path path, @Nullable List remainingNames) { if (scope instanceof TableScope) { scope = scope.getValidator().getSelectScope((SqlSelect) scope.getNode()); } @@ -323,13 +323,13 @@ public void clear() { class Resolve { public final SqlValidatorNamespace namespace; private final boolean nullable; - public final SqlValidatorScope scope; // may be null + public final @Nullable SqlValidatorScope scope; // may be null public final Path path; /** Names not matched; empty if it was a full match. */ final List remainingNames; Resolve(SqlValidatorNamespace namespace, boolean nullable, - SqlValidatorScope scope, Path path, @Nullable List remainingNames) { + @Nullable SqlValidatorScope scope, Path path, @Nullable List remainingNames) { this.namespace = Objects.requireNonNull(namespace); this.nullable = nullable; this.scope = scope; 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 7c9cff950e94..e0a6efa95d41 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 @@ -102,11 +102,11 @@ private SqlValidatorUtil() {} * @param usedDataset Output parameter which is set to true if a sample * dataset is found; may be null */ - public static RelOptTable getRelOptTable( + public static @Nullable RelOptTable getRelOptTable( SqlValidatorNamespace namespace, Prepare.CatalogReader catalogReader, - String datasetName, - boolean[] usedDataset) { + @Nullable String datasetName, + boolean @Nullable [] usedDataset) { if (namespace.isWrapperFor(TableNamespace.class)) { final TableNamespace tableNamespace = namespace.unwrap(TableNamespace.class); @@ -129,11 +129,11 @@ public static RelOptTable getRelOptTable( return null; } - private static RelOptTable getRelOptTable( + private static @Nullable RelOptTable getRelOptTable( TableNamespace tableNamespace, Prepare.CatalogReader catalogReader, - String datasetName, - boolean[] usedDataset, + @Nullable String datasetName, + boolean @Nullable [] usedDataset, List extendedFields) { final List names = tableNamespace.getTable().getQualifiedName(); RelOptTable table; @@ -146,7 +146,7 @@ private static RelOptTable getRelOptTable( // Schema does not support substitution. Ignore the data set, if any. table = catalogReader.getTableForMember(names); } - if (!extendedFields.isEmpty()) { + if (table != null && !extendedFields.isEmpty()) { table = table.extend(extendedFields); } return table; @@ -246,7 +246,7 @@ public static Map mapNameToIndex(List fields) } @Deprecated // to be removed before 2.0 - public static RelDataTypeField lookupField(boolean caseSensitive, + public static @Nullable RelDataTypeField lookupField(boolean caseSensitive, final RelDataType rowType, String columnName) { return rowType.getField(columnName, caseSensitive, false); } @@ -368,7 +368,7 @@ public static SqlValidatorWithHints newValidator( * @param suggester Base for name when input name is null * @return Unique name */ - public static String uniquify(String name, Set usedNames, + public static String uniquify(@Nullable String name, Set usedNames, Suggester suggester) { if (name != null) { if (usedNames.add(name)) { @@ -597,7 +597,7 @@ private static void addFields(List fieldList, public static @Nullable RelDataTypeField getTargetField( RelDataType rowType, RelDataTypeFactory typeFactory, SqlIdentifier id, SqlValidatorCatalogReader catalogReader, - RelOptTable table) { + @Nullable RelOptTable table) { final Table t = table == null ? null : table.unwrap(Table.class); if (!(t instanceof CustomColumnResolvingTable)) { final SqlNameMatcher nameMatcher = catalogReader.nameMatcher(); @@ -1058,7 +1058,7 @@ public static ImmutableList cube( return schema; } - private static CalciteSchema.TableEntry getTableEntryFrom( + private static CalciteSchema.@Nullable TableEntry getTableEntryFrom( CalciteSchema schema, String name, boolean caseSensitive) { CalciteSchema.TableEntry entry = schema.getTable(name, caseSensitive); diff --git a/core/src/main/java/org/apache/calcite/sql/validate/TableConstructorNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/TableConstructorNamespace.java index 4dcf36efcb02..69f2e6b378b2 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/TableConstructorNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/TableConstructorNamespace.java @@ -20,6 +20,8 @@ import org.apache.calcite.sql.SqlCall; import org.apache.calcite.sql.SqlNode; +import org.checkerframework.checker.nullness.qual.Nullable; + import static org.apache.calcite.util.Static.RESOURCE; /** @@ -65,7 +67,7 @@ protected RelDataType validateImpl(RelDataType targetRowType) { return tableConstructorRowType; } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return values; } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/TableNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/TableNamespace.java index 9555e504601f..7605ffcbaba0 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/TableNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/TableNamespace.java @@ -67,12 +67,12 @@ protected RelDataType validateImpl(RelDataType targetRowType) { return builder.build(); } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { // This is the only kind of namespace not based on a node in the parse tree. return null; } - @Override public @Nullable SqlValidatorTable getTable() { + @Override public SqlValidatorTable getTable() { return table; } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java index bae738771914..6b430c00f935 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/UnnestNamespace.java @@ -70,7 +70,7 @@ protected RelDataType validateImpl(RelDataType targetRowType) { return toStruct(type, unnest); } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return unnest; } } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/WithItemNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/WithItemNamespace.java index f7449abacd98..5caed417b658 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/WithItemNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/WithItemNamespace.java @@ -24,6 +24,8 @@ import org.apache.calcite.sql.SqlWithItem; import org.apache.calcite.util.Pair; +import org.checkerframework.checker.nullness.qual.Nullable; + /** Very similar to {@link AliasNamespace}. */ class WithItemNamespace extends AbstractNamespace { private final SqlWithItem withItem; @@ -51,7 +53,7 @@ class WithItemNamespace extends AbstractNamespace { return builder.build(); } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return withItem; } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/WithNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/WithNamespace.java index f1e8914a8452..4589c9cfa590 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/WithNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/WithNamespace.java @@ -22,6 +22,8 @@ import org.apache.calcite.sql.SqlWithItem; import org.apache.calcite.util.Util; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Namespace for WITH clause. */ @@ -60,7 +62,7 @@ protected RelDataType validateImpl(RelDataType targetRowType) { return rowType; } - public SqlNode getNode() { + public @Nullable SqlNode getNode() { return with; } } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/WithScope.java b/core/src/main/java/org/apache/calcite/sql/validate/WithScope.java index 3bfa84746571..231e531abe54 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/WithScope.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/WithScope.java @@ -20,6 +20,8 @@ import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlWithItem; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** Scope providing the objects that are available after evaluating an item @@ -47,7 +49,7 @@ public SqlNode getNode() { return withItem; } - @Override public SqlValidatorNamespace getTableNamespace(List names) { + @Override public @Nullable SqlValidatorNamespace getTableNamespace(List names) { if (names.size() == 1 && names.get(0).equals(withItem.name.getSimple())) { return validator.getNamespace(withItem); } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java b/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java index fcb424ee32b9..f22ae459783f 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/implicit/AbstractTypeCoercion.java @@ -42,6 +42,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; @@ -324,7 +326,8 @@ protected void updateInferredColumnType( * * @return tightest common type, i.e. INTEGER + DECIMAL(10, 2) returns DECIMAL(10, 2) */ - public RelDataType getTightestCommonType(RelDataType type1, RelDataType type2) { + public @Nullable RelDataType getTightestCommonType( + @Nullable RelDataType type1, @Nullable RelDataType type2) { if (type1 == null || type2 == null) { return null; } @@ -405,8 +408,12 @@ public RelDataType getTightestCommonType(RelDataType type1, RelDataType type2) { /** * Promote all the way to VARCHAR. */ - private RelDataType promoteToVarChar(RelDataType type1, RelDataType type2) { + private @Nullable RelDataType promoteToVarChar( + @Nullable RelDataType type1, @Nullable RelDataType type2) { RelDataType resultType = null; + if (type1 == null || type2 == null) { + return null; + } // No promotion for char and varchar. if (SqlTypeUtil.isCharacter(type1) && SqlTypeUtil.isCharacter(type2)) { return null; @@ -430,7 +437,12 @@ private RelDataType promoteToVarChar(RelDataType type1, RelDataType type2) { * other is not. For date + timestamp operands, use timestamp as common type, * i.e. Timestamp(2017-01-01 00:00 ...) > Date(2018) evaluates to be false. */ - public RelDataType commonTypeForBinaryComparison(RelDataType type1, RelDataType type2) { + public @Nullable RelDataType commonTypeForBinaryComparison( + @Nullable RelDataType type1, @Nullable RelDataType type2) { + if (type1 == null || type2 == null) { + return null; + } + SqlTypeName typeName1 = type1.getSqlTypeName(); SqlTypeName typeName2 = type2.getSqlTypeName(); @@ -508,10 +520,13 @@ public RelDataType commonTypeForBinaryComparison(RelDataType type1, RelDataType * is that we allow some precision loss when widening decimal to fractional, * or promote fractional to string type. */ - public RelDataType getWiderTypeForTwo( - RelDataType type1, - RelDataType type2, + public @Nullable RelDataType getWiderTypeForTwo( + @Nullable RelDataType type1, + @Nullable RelDataType type2, boolean stringPromotion) { + if (type1 == null || type2 == null) { + return null; + } RelDataType resultType = getTightestCommonType(type1, type2); if (null == resultType) { resultType = getWiderTypeForDecimal(type1, type2); @@ -542,7 +557,11 @@ public RelDataType getWiderTypeForTwo( * you can override it based on the specific system requirement in * {@link org.apache.calcite.rel.type.RelDataTypeSystem}. */ - public RelDataType getWiderTypeForDecimal(RelDataType type1, RelDataType type2) { + public @Nullable RelDataType getWiderTypeForDecimal( + @Nullable RelDataType type1, @Nullable RelDataType type2) { + if (type1 == null || type2 == null) { + return null; + } if (!SqlTypeUtil.isDecimal(type1) && !SqlTypeUtil.isDecimal(type2)) { return null; } @@ -564,7 +583,8 @@ public RelDataType getWiderTypeForDecimal(RelDataType type1, RelDataType type2) * {@link #getWiderTypeForTwo} satisfies the associative law. For instance, * (DATE, INTEGER, VARCHAR) should have VARCHAR as the wider common type. */ - public RelDataType getWiderTypeFor(List typeList, boolean stringPromotion) { + public @Nullable RelDataType getWiderTypeFor(List typeList, + boolean stringPromotion) { assert typeList.size() > 1; RelDataType resultType = typeList.get(0); @@ -632,7 +652,7 @@ boolean canImplicitTypeCast(List types, List familie * @param expected Expected {@link SqlTypeFamily} of registered SqlFunction * @return common type of implicit cast, null if we do not find any */ - public RelDataType implicitCast(RelDataType in, SqlTypeFamily expected) { + public @Nullable RelDataType implicitCast(RelDataType in, SqlTypeFamily expected) { List numericFamilies = ImmutableList.of( SqlTypeFamily.NUMERIC, SqlTypeFamily.DECIMAL, diff --git a/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercion.java b/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercion.java index 3b0d06457250..740b3e50fd3d 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercion.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercion.java @@ -24,6 +24,8 @@ import org.apache.calcite.sql.type.SqlTypeFamily; import org.apache.calcite.sql.validate.SqlValidatorScope; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -54,14 +56,16 @@ public interface TypeCoercion { * * @return common type */ - RelDataType getTightestCommonType(RelDataType type1, RelDataType type2); + @Nullable RelDataType getTightestCommonType( + @Nullable RelDataType type1, @Nullable RelDataType type2); /** * Case2: type widening. The main difference with * {@link #getTightestCommonType} is that we allow * some precision loss when widening decimal to fractional, or promote to string type. */ - RelDataType getWiderTypeForTwo(RelDataType type1, RelDataType type2, boolean stringPromotion); + @Nullable RelDataType getWiderTypeForTwo(@Nullable RelDataType type1, @Nullable RelDataType type2, + boolean stringPromotion); /** * Similar to {@link #getWiderTypeForTwo}, but can handle @@ -71,7 +75,7 @@ public interface TypeCoercion { * {@link #getWiderTypeForTwo} satisfies the associative law. For instance, * (DATE, INTEGER, VARCHAR) should have VARCHAR as the wider common type. */ - RelDataType getWiderTypeFor(List typeList, boolean stringPromotion); + @Nullable RelDataType getWiderTypeFor(List typeList, boolean stringPromotion); /** * Finds a wider type when one or both types are DECIMAL type. @@ -85,13 +89,15 @@ public interface TypeCoercion { * you can override it based on the specific system requirement in * {@link org.apache.calcite.rel.type.RelDataTypeSystem}. */ - RelDataType getWiderTypeForDecimal(RelDataType type1, RelDataType type2); + @Nullable RelDataType getWiderTypeForDecimal( + @Nullable RelDataType type1, @Nullable RelDataType type2); /** * Determines common type for a comparison operator whose operands are STRING * type and the other (non STRING) type. */ - RelDataType commonTypeForBinaryComparison(RelDataType type1, RelDataType type2); + @Nullable RelDataType commonTypeForBinaryComparison( + @Nullable RelDataType type1, @Nullable RelDataType type2); /** * Widen a SqlNode ith column type to target type, mainly used for set diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java index 17eff4cb3b8b..b52cd8d46db3 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java @@ -120,6 +120,8 @@ import java.util.stream.Collectors; import javax.annotation.Nonnull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * RelDecorrelator replaces all correlated expressions (corExp) in a relational * expression (RelNode) tree with non-correlated expressions that are produced @@ -225,7 +227,7 @@ public static RelNode decorrelateQuery(RelNode rootRel, return newRootRel; } - private void setCurrent(RelNode root, Correlate corRel) { + private void setCurrent(RelNode root, @Nullable Correlate corRel) { currentRel = corRel; if (corRel != null) { cm = new CorelMapBuilder().build(Util.first(root, corRel)); @@ -302,7 +304,7 @@ protected RelNode decorrelate(RelNode root) { return root; } - private Function2 createCopyHook() { + private Function2 createCopyHook() { return (oldNode, newNode) -> { if (cm.mapRefRelToCorRef.containsKey(oldNode)) { cm.mapRefRelToCorRef.putAll(newNode, @@ -389,7 +391,7 @@ protected RexNode removeCorrelationExpr( } /** Fallback if none of the other {@code decorrelateRel} methods match. */ - public Frame decorrelateRel(RelNode rel) { + public @Nullable Frame decorrelateRel(RelNode rel) { RelNode newRel = rel.copy(rel.getTraitSet(), rel.getInputs()); if (rel.getInputs().size() > 0) { @@ -417,7 +419,7 @@ public Frame decorrelateRel(RelNode rel) { ImmutableSortedMap.of()); } - public Frame decorrelateRel(Sort rel) { + public @Nullable Frame decorrelateRel(Sort rel) { // // Rewrite logic: // @@ -465,16 +467,16 @@ public Frame decorrelateRel(Sort rel) { return register(rel, newSort, frame.oldToNewOutputs, frame.corDefOutputs); } - public Frame decorrelateRel(Values rel) { + public @Nullable Frame decorrelateRel(Values rel) { // There are no inputs, so rel does not need to be changed. return null; } - public Frame decorrelateRel(LogicalAggregate rel) { + public @Nullable Frame decorrelateRel(LogicalAggregate rel) { return decorrelateRel((Aggregate) rel); } - public Frame decorrelateRel(Aggregate rel) { + public @Nullable Frame decorrelateRel(Aggregate rel) { // // Rewrite logic: // @@ -682,7 +684,7 @@ private static void shiftMapping(Map mapping, int startIndex, } } - public Frame getInvoke(RelNode r, RelNode parent) { + public @Nullable Frame getInvoke(RelNode r, @Nullable RelNode parent) { final Frame frame = dispatcher.invoke(r); if (frame != null) { map.put(r, frame); @@ -703,11 +705,11 @@ public Frame getInvoke(RelNode r, RelNode parent) { return null; } - public Frame decorrelateRel(LogicalProject rel) { + public @Nullable Frame decorrelateRel(LogicalProject rel) { return decorrelateRel((Project) rel); } - public Frame decorrelateRel(Project rel) { + public @Nullable Frame decorrelateRel(Project rel) { // // Rewrite logic: // @@ -774,7 +776,7 @@ public Frame decorrelateRel(Project rel) { * generated * @return RelNode the root of the resultant RelNode tree */ - private RelNode createValueGenerator( + private @Nullable RelNode createValueGenerator( Iterable correlations, int valueGenFieldOffset, SortedMap corDefOutputs) { @@ -879,7 +881,7 @@ private RelNode createValueGenerator( return r; } - private Frame getFrame(RelNode r, boolean safe) { + private @Nullable Frame getFrame(RelNode r, boolean safe) { final Frame frame = map.get(r); if (frame == null && safe) { return new Frame(r, r, ImmutableSortedMap.of(), @@ -1055,25 +1057,25 @@ private boolean isWidening(RelDataType type, RelDataType type1) { && type.getPrecision() >= type1.getPrecision(); } - public Frame decorrelateRel(LogicalSnapshot rel) { + public @Nullable Frame decorrelateRel(LogicalSnapshot rel) { if (RexUtil.containsCorrelation(rel.getPeriod())) { return null; } return decorrelateRel((RelNode) rel); } - public Frame decorrelateRel(LogicalTableFunctionScan rel) { + public @Nullable Frame decorrelateRel(LogicalTableFunctionScan rel) { if (RexUtil.containsCorrelation(rel.getCall())) { return null; } return decorrelateRel((RelNode) rel); } - public Frame decorrelateRel(LogicalFilter rel) { + public @Nullable Frame decorrelateRel(LogicalFilter rel) { return decorrelateRel((Filter) rel); } - public Frame decorrelateRel(Filter rel) { + public @Nullable Frame decorrelateRel(Filter rel) { // // Rewrite logic: // @@ -1112,7 +1114,7 @@ public Frame decorrelateRel(Filter rel) { // Replace the filter expression to reference output of the join // Map filter to the new filter over join relBuilder.push(frame.r) - .filter(decorrelateExpr(currentRel, map, cm2, rel.getCondition())); + .filter(decorrelateExpr(castNonNull(currentRel), map, cm2, rel.getCondition())); // Filter does not change the input ordering. // Filter rel does not permute the input. @@ -1122,11 +1124,11 @@ public Frame decorrelateRel(Filter rel) { frame.corDefOutputs); } - public Frame decorrelateRel(LogicalCorrelate rel) { + public @Nullable Frame decorrelateRel(LogicalCorrelate rel) { return decorrelateRel((Correlate) rel); } - public Frame decorrelateRel(Correlate rel) { + public @Nullable Frame decorrelateRel(Correlate rel) { // // Rewrite logic: // @@ -1225,11 +1227,11 @@ public Frame decorrelateRel(Correlate rel) { return register(rel, newJoin, mapOldToNewOutputs, corDefOutputs); } - public Frame decorrelateRel(LogicalJoin rel) { + public @Nullable Frame decorrelateRel(LogicalJoin rel) { return decorrelateRel((Join) rel); } - public Frame decorrelateRel(Join rel) { + public @Nullable Frame decorrelateRel(Join rel) { // For SEMI/ANTI join decorrelate it's input directly, // because the correlate variables can only be propagated from // the left side, which is not supported yet. @@ -1258,7 +1260,7 @@ public Frame decorrelateRel(Join rel) { .push(leftFrame.r) .push(rightFrame.r) .join(rel.getJoinType(), - decorrelateExpr(currentRel, map, cm, rel.getCondition()), + decorrelateExpr(castNonNull(currentRel), map, cm, rel.getCondition()), ImmutableSet.of()) .hints(rel.getHints()) .build(); @@ -1459,9 +1461,9 @@ private RelNode aggregateCorrelatorOutput( */ private boolean checkCorVars( Correlate correlate, - Project project, - Filter filter, - List correlatedJoinKeys) { + @Nullable Project project, + @Nullable Filter filter, + @Nullable List correlatedJoinKeys) { if (filter != null) { assert correlatedJoinKeys != null; @@ -1633,13 +1635,13 @@ private class RemoveCorrelationRexShuttle extends RexShuttle { final RexBuilder rexBuilder; final RelDataTypeFactory typeFactory; final boolean projectPulledAboveLeftCorrelator; - final RexInputRef nullIndicator; + final @Nullable RexInputRef nullIndicator; final ImmutableSet isCount; RemoveCorrelationRexShuttle( RexBuilder rexBuilder, boolean projectPulledAboveLeftCorrelator, - RexInputRef nullIndicator, + @Nullable RexInputRef nullIndicator, Set isCount) { this.projectPulledAboveLeftCorrelator = projectPulledAboveLeftCorrelator; @@ -1651,7 +1653,7 @@ private class RemoveCorrelationRexShuttle extends RexShuttle { private RexNode createCaseExpression( RexInputRef nullInputRef, - RexLiteral lit, + @Nullable RexLiteral lit, RexNode rexNode) { RexNode[] caseOperands = new RexNode[3]; @@ -1736,7 +1738,7 @@ private RexNode createCaseExpression( RexInputRef newInputRef = new RexInputRef(leftInputFieldCount + pos, newType); - if ((isCount != null) && isCount.contains(pos)) { + if (isCount.contains(pos)) { return createCaseExpression( newInputRef, rexBuilder.makeExactLiteral(BigDecimal.ZERO), 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 fb06e48ccc8c..b941e72e5702 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java @@ -182,7 +182,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import java.lang.reflect.Type; diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java index 30d3e38ad09a..02ce61d5c6c6 100644 --- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java +++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java @@ -566,7 +566,7 @@ public ImmutableList fields(Iterable fieldNames) { /** Returns references to fields identified by a mapping. */ public ImmutableList fields(Mappings.TargetMapping mapping) { - return fields(Mappings.asList(mapping)); + return fields(Mappings.asListNonNull(mapping)); } /** Creates an access to a field by name. */ diff --git a/core/src/main/java/org/apache/calcite/util/ChunkList.java b/core/src/main/java/org/apache/calcite/util/ChunkList.java index d3116a843a1b..ed367484d90b 100644 --- a/core/src/main/java/org/apache/calcite/util/ChunkList.java +++ b/core/src/main/java/org/apache/calcite/util/ChunkList.java @@ -158,7 +158,7 @@ private static void setPrev(E[] chunk, E @Nullable [] prev) { chunk[0] = (E) prev; } - private static E @Nullable [] next(E[] chunk) { + private static E @Nullable [] next(E[] chunk) { //noinspection unchecked return (E @Nullable []) chunk[1]; } diff --git a/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java b/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java index 946ca8ab274e..a6834ef003d9 100644 --- a/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java +++ b/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java @@ -26,6 +26,7 @@ import org.checkerframework.checker.initialization.qual.UnderInitialization; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.RequiresNonNull; import org.checkerframework.dataflow.qual.Pure; import java.io.Serializable; @@ -45,7 +46,7 @@ import java.util.TreeMap; import javax.annotation.Nonnull; -import static org.apache.calcite.linq4j.Nullness.assertNonNull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; /** * An immutable list of bits. @@ -884,7 +885,11 @@ public BitSet toBitSet() { public ImmutableBitSet permute(Map map) { final Builder builder = builder(); for (int i = nextSetBit(0); i >= 0; i = nextSetBit(i + 1)) { - builder.set(map.get(i)); + Integer value = map.get(i); + if (value == null) { + throw new NullPointerException("Index " + i + " is not mapped in " + map); + } + builder.set(value); } return builder.build(); } @@ -931,7 +936,7 @@ public static boolean allContain(Collection bitSets, int bit) { * from the lowest element in the Set. */ private static class Closure { - private SortedMap equivalence; + private final SortedMap equivalence; private final SortedMap closure = new TreeMap<>(); @@ -944,6 +949,7 @@ private static class Closure { } } + @RequiresNonNull("equivalence") private ImmutableBitSet computeClosure( @UnderInitialization Closure this, int pos @@ -952,7 +958,7 @@ private ImmutableBitSet computeClosure( if (o != null) { return o; } - final ImmutableBitSet b = equivalence.get(pos); + final ImmutableBitSet b = castNonNull(equivalence.get(pos)); o = b; int i = b.nextSetBit(pos + 1); for (; i >= 0; i = b.nextSetBit(i + 1)) { @@ -1050,7 +1056,10 @@ public boolean get(int bitIndex) { } private void trim(int wordCount) { - while (wordCount > 0 && assertNonNull(words)[wordCount - 1] == 0L) { + if (words == null) { + throw new IllegalArgumentException("can only use builder once"); + } + while (wordCount > 0 && words[wordCount - 1] == 0L) { --wordCount; } if (wordCount == words.length) { @@ -1064,6 +1073,9 @@ private void trim(int wordCount) { } public Builder clear(int bit) { + if (words == null) { + throw new IllegalArgumentException("can only use builder once"); + } int wordIndex = wordIndex(bit); if (wordIndex < words.length) { words[wordIndex] &= ~(1L << bit); @@ -1125,10 +1137,14 @@ public Builder removeAll(ImmutableBitSet bitSet) { /** Sets a range of bits, from {@code from} to {@code to} - 1. */ public Builder set(int fromIndex, int toIndex) { if (fromIndex > toIndex) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("fromIndex(" + fromIndex + ")" + + " > toIndex(" + toIndex + ")"); } if (toIndex < 0) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("toIndex(" + toIndex + ") < 0"); + } + if (words == null) { + throw new IllegalArgumentException("can only use builder once"); } if (fromIndex < toIndex) { // Increase capacity if necessary @@ -1156,10 +1172,16 @@ public Builder set(int fromIndex, int toIndex) { } public boolean isEmpty() { + if (words == null) { + throw new IllegalArgumentException("can only use builder once"); + } return words.length == 0; } public void intersect(ImmutableBitSet that) { + if (words == null) { + throw new IllegalArgumentException("can only use builder once"); + } int x = Math.min(words.length, that.words.length); for (int i = 0; i < x; i++) { words[i] &= that.words[i]; diff --git a/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java b/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java index c1b6f0075c18..6cbc5efb309e 100644 --- a/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java +++ b/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java @@ -26,7 +26,6 @@ import com.google.common.collect.UnmodifiableListIterator; import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.checker.nullness.qual.PolyNull; import java.lang.reflect.Array; import java.util.ArrayList; @@ -39,6 +38,7 @@ import java.util.NoSuchElementException; import static org.apache.calcite.linq4j.Nullness.assertNonNull; +import static org.apache.calcite.linq4j.Nullness.castNonNull; /** * An immutable list of {@link Integer} values backed by an array of @@ -117,12 +117,13 @@ private static ImmutableIntList copyFromCollection( return Arrays.hashCode(ints); } + @SuppressWarnings("contracts.conditional.postcondition.not.satisfied") @Override public boolean equals(@Nullable Object obj) { - return this == obj - || obj instanceof ImmutableIntList + return ((this == obj) + || (obj instanceof ImmutableIntList)) ? Arrays.equals(ints, ((ImmutableIntList) obj).ints) - : obj instanceof List - && obj.equals(this); + : ((obj instanceof List) + && obj.equals(this)); } @Override public String toString() { @@ -145,9 +146,9 @@ public Object[] toArray() { return objects; } - public T @PolyNull [] toArray(T @PolyNull [] a) { + public @Nullable T[] toArray(T @Nullable [] a) { final int size = ints.length; - if (a.length < size) { + if (castNonNull(a).length < size) { // Make a new array of a's runtime type, but my contents: a = a.getClass() == Object[].class ? (T[]) new Object[size] @@ -163,7 +164,7 @@ public Object[] toArray() { System.arraycopy(toArray(), 0, a, 0, size); } if (a.length > size) { - a[size] = null; + a[size] = castNonNull(null); } return a; } @@ -298,9 +299,9 @@ private static class EmptyImmutableIntList extends ImmutableIntList { return EMPTY_ARRAY; } - @Override public T @PolyNull [] toArray(T @PolyNull [] a) { - if (a.length > 0) { - a[0] = null; + @Override public @Nullable T[] toArray(T @Nullable [] a) { + if (castNonNull(a).length > 0) { + a[0] = castNonNull(null); } return a; } diff --git a/core/src/main/java/org/apache/calcite/util/Litmus.java b/core/src/main/java/org/apache/calcite/util/Litmus.java index ab5e29841985..1ae60a9a59b3 100644 --- a/core/src/main/java/org/apache/calcite/util/Litmus.java +++ b/core/src/main/java/org/apache/calcite/util/Litmus.java @@ -26,7 +26,7 @@ public interface Litmus { /** Implementation of {@link org.apache.calcite.util.Litmus} that throws * an {@link java.lang.AssertionError} on failure. */ Litmus THROW = new Litmus() { - public boolean fail(@Nullable String message, Object... args) { + public boolean fail(@Nullable String message, @Nullable Object... args) { final String s = message == null ? null : MessageFormatter.arrayFormat(message, args).getMessage(); throw new AssertionError(s); @@ -36,7 +36,7 @@ public boolean succeed() { return true; } - public boolean check(boolean condition, @Nullable String message, Object... args) { + public boolean check(boolean condition, @Nullable String message, @Nullable Object... args) { if (condition) { return succeed(); } else { @@ -48,7 +48,7 @@ public boolean check(boolean condition, @Nullable String message, Object... args /** Implementation of {@link org.apache.calcite.util.Litmus} that returns * a status code but does not throw. */ Litmus IGNORE = new Litmus() { - public boolean fail(@Nullable String message, Object... args) { + public boolean fail(@Nullable String message, @Nullable Object... args) { return false; } @@ -56,7 +56,7 @@ public boolean succeed() { return true; } - public boolean check(boolean condition, @Nullable String message, Object... args) { + public boolean check(boolean condition, @Nullable String message, @Nullable Object... args) { return condition; } }; @@ -66,7 +66,7 @@ public boolean check(boolean condition, @Nullable String message, Object... args * @param message Message * @param args Arguments */ - boolean fail(@Nullable String message, Object... args); + boolean fail(@Nullable String message, @Nullable Object... args); /** Called when test succeeds. Returns true. */ boolean succeed(); @@ -77,5 +77,5 @@ public boolean check(boolean condition, @Nullable String message, Object... args * if the condition is false, calls {@link #fail}, * converting {@code info} into a string message. */ - boolean check(boolean condition, @Nullable String message, Object... args); + boolean check(boolean condition, @Nullable String message, @Nullable Object... args); } diff --git a/core/src/main/java/org/apache/calcite/util/NlsString.java b/core/src/main/java/org/apache/calcite/util/NlsString.java index e328bb61f578..e1d6ffe1bd97 100644 --- a/core/src/main/java/org/apache/calcite/util/NlsString.java +++ b/core/src/main/java/org/apache/calcite/util/NlsString.java @@ -28,6 +28,7 @@ import com.google.common.cache.LoadingCache; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; import java.nio.ByteBuffer; import java.nio.charset.CharacterCodingException; @@ -179,14 +180,17 @@ public int hashCode() { return getValue().compareTo(other.getValue()); } + @Pure public @Nullable String getCharsetName() { return charsetName; } + @Pure public @Nullable Charset getCharset() { return charset; } + @Pure public @Nullable SqlCollation getCollation() { return collation; } @@ -298,6 +302,7 @@ public NlsString copy(String value) { } /** Returns the value as a {@link ByteString}. */ + @Pure public @Nullable ByteString getValueBytes() { return bytesValue; } diff --git a/core/src/main/java/org/apache/calcite/util/Pair.java b/core/src/main/java/org/apache/calcite/util/Pair.java index f7fc9bc7a9dc..f2d9d1907bf7 100644 --- a/core/src/main/java/org/apache/calcite/util/Pair.java +++ b/core/src/main/java/org/apache/calcite/util/Pair.java @@ -17,6 +17,7 @@ package org.apache.calcite.util; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.PolyNull; import java.io.Serializable; import java.util.AbstractList; @@ -286,11 +287,11 @@ public static List> zipMutable( * @param Right type */ public static void forEach( - final Iterable ks, - final Iterable vs, - BiConsumer consumer) { - final Iterator leftIterator = ks.iterator(); - final Iterator rightIterator = vs.iterator(); + final Iterable ks, + final Iterable vs, + BiConsumer<@PolyNull K, @PolyNull V> consumer) { + final Iterator leftIterator = ks.iterator(); + final Iterator rightIterator = vs.iterator(); while (leftIterator.hasNext() && rightIterator.hasNext()) { consumer.accept(leftIterator.next(), rightIterator.next()); } diff --git a/core/src/main/java/org/apache/calcite/util/Sarg.java b/core/src/main/java/org/apache/calcite/util/Sarg.java index 2d460c5799af..31c0b0fb0673 100644 --- a/core/src/main/java/org/apache/calcite/util/Sarg.java +++ b/core/src/main/java/org/apache/calcite/util/Sarg.java @@ -23,6 +23,8 @@ import com.google.common.collect.Range; import com.google.common.collect.RangeSet; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Objects; import java.util.function.BiConsumer; @@ -123,11 +125,11 @@ public StringBuilder printTo(StringBuilder sb, return RangeSets.hashCode(rangeSet) * 31 + (containsNull ? 2 : 3); } - @Override public boolean equals(Object o) { + @Override public boolean equals(@Nullable Object o) { return o == this || o instanceof Sarg - && rangeSet.equals(((Sarg) o).rangeSet) - && containsNull == ((Sarg) o).containsNull; + && containsNull == ((Sarg) o).containsNull + && rangeSet.equals(((Sarg) o).rangeSet); } /** Returns whether this Sarg is a collection of 1 or more points (and perhaps diff --git a/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java b/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java index c58932e7b933..e0b51c2d3703 100644 --- a/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java +++ b/core/src/main/java/org/apache/calcite/util/mapping/Mappings.java @@ -25,7 +25,7 @@ import com.google.common.collect.Iterables; import com.google.common.primitives.Ints; -import org.checkerframework.checker.initialization.qual.UnderInitialization; +import org.checkerframework.checker.initialization.qual.UnknownInitialization; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.AbstractList; @@ -36,6 +36,7 @@ import java.util.List; import java.util.Map; import java.util.function.IntFunction; +import javax.annotation.CheckReturnValue; /** * Utility functions related to mappings. @@ -314,10 +315,12 @@ public int size() { * {@code mapping.getSourceCount()}. * *

    Converse of {@link #target(List, int)}

    + * @see #asListNonNull(TargetMapping) */ - public static List asList(final TargetMapping mapping) { - return new AbstractList() { - public Integer get(int source) { + @CheckReturnValue + public static List<@Nullable Integer> asList(final TargetMapping mapping) { + return new AbstractList<@Nullable Integer>() { + public @Nullable Integer get(int source) { int target = mapping.getTargetOpt(source); return target < 0 ? null : target; } @@ -338,6 +341,7 @@ public int size() { *

    Converse of {@link #target(List, int)}

    * @see #asList(TargetMapping) */ + @CheckReturnValue public static List asListNonNull(final TargetMapping mapping) { return new AbstractList() { public Integer get(int source) { @@ -1345,7 +1349,7 @@ public boolean hasNext() { } private void advance( - @UnderInitialization MappingItr this + @UnknownInitialization MappingItr this ) { do { ++i; diff --git a/core/src/main/java/org/apache/calcite/util/trace/CalciteTrace.java b/core/src/main/java/org/apache/calcite/util/trace/CalciteTrace.java index bf94a6f09f8a..e2b0fcfbbd8b 100644 --- a/core/src/main/java/org/apache/calcite/util/trace/CalciteTrace.java +++ b/core/src/main/java/org/apache/calcite/util/trace/CalciteTrace.java @@ -23,6 +23,7 @@ import org.apache.calcite.plan.RelOptPlanner; import org.apache.calcite.prepare.Prepare; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,7 +57,7 @@ public abstract class CalciteTrace { */ public static final Logger PARSER_LOGGER = getParserTracer(); - private static final ThreadLocal> DYNAMIC_HANDLER = + private static final ThreadLocal<@Nullable Function2> DYNAMIC_HANDLER = ThreadLocal.withInitial(Functions::ignore2); //~ Methods ---------------------------------------------------------------- @@ -145,7 +146,7 @@ public static Logger getTestTracer(Class testClass) { * It exists for unit-testing. * The handler is never null; the default handler does nothing. */ - public static ThreadLocal> getDynamicHandler() { + public static ThreadLocal<@Nullable Function2> getDynamicHandler() { return DYNAMIC_HANDLER; } } diff --git a/core/src/test/java/org/apache/calcite/plan/volcano/CollationConversionTest.java b/core/src/test/java/org/apache/calcite/plan/volcano/CollationConversionTest.java index 02caab20d3ff..dc18a6d65881 100644 --- a/core/src/test/java/org/apache/calcite/plan/volcano/CollationConversionTest.java +++ b/core/src/test/java/org/apache/calcite/plan/volcano/CollationConversionTest.java @@ -37,6 +37,7 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; import org.junit.jupiter.api.Test; import java.util.List; @@ -258,7 +259,7 @@ public RelCollation getDefault() { return LEAF_COLLATION; } - public RelNode convert(RelOptPlanner planner, RelNode rel, + public @Nullable RelNode convert(RelOptPlanner planner, RelNode rel, RelCollation toCollation, boolean allowInfiniteCostConverters) { if (toCollation.getFieldCollations().isEmpty()) { // An empty sort doesn't make sense. diff --git a/core/src/test/java/org/apache/calcite/plan/volcano/TraitConversionTest.java b/core/src/test/java/org/apache/calcite/plan/volcano/TraitConversionTest.java index 0906a1e0dc27..c2485e850031 100644 --- a/core/src/test/java/org/apache/calcite/plan/volcano/TraitConversionTest.java +++ b/core/src/test/java/org/apache/calcite/plan/volcano/TraitConversionTest.java @@ -30,6 +30,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.metadata.RelMetadataQuery; +import org.checkerframework.checker.nullness.qual.Nullable; import org.junit.jupiter.api.Test; import java.util.List; @@ -257,7 +258,7 @@ private static class ConvertRelDistributionTraitDef return "ConvertRelDistributionTraitDef"; } - @Override public RelNode convert(RelOptPlanner planner, RelNode rel, + @Override public @Nullable RelNode convert(RelOptPlanner planner, RelNode rel, SimpleDistribution toTrait, boolean allowInfiniteCostConverters) { if (toTrait == SIMPLE_DISTRIBUTION_ANY) { return rel; diff --git a/core/src/test/java/org/apache/calcite/plan/volcano/VolcanoPlannerTraitTest.java b/core/src/test/java/org/apache/calcite/plan/volcano/VolcanoPlannerTraitTest.java index 174beff933eb..82eb7f666d26 100644 --- a/core/src/test/java/org/apache/calcite/plan/volcano/VolcanoPlannerTraitTest.java +++ b/core/src/test/java/org/apache/calcite/plan/volcano/VolcanoPlannerTraitTest.java @@ -44,6 +44,7 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import org.checkerframework.checker.nullness.qual.Nullable; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -322,7 +323,7 @@ public AltTrait getDefault() { return ALT_TRAIT; } - public RelNode convert( + public @Nullable RelNode convert( RelOptPlanner planner, RelNode rel, AltTrait toTrait, 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 a357fceb1ae2..a1b0e84476a9 100644 --- a/core/src/test/java/org/apache/calcite/test/MockRelOptPlanner.java +++ b/core/src/test/java/org/apache/calcite/test/MockRelOptPlanner.java @@ -32,6 +32,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -66,7 +68,7 @@ public void setRoot(RelNode rel) { } // implement RelOptPlanner - public RelNode getRoot() { + public @Nullable RelNode getRoot() { return root; } @@ -188,7 +190,7 @@ private boolean match( // implement RelOptPlanner public RelNode register( RelNode rel, - RelNode equivRel) { + @Nullable RelNode equivRel) { return rel; }