From 2b61b9c74d21a5c972042b1333326628011ae5e4 Mon Sep 17 00:00:00 2001 From: Vladimir Sitnikov Date: Thu, 1 Oct 2020 17:04:42 +0300 Subject: [PATCH] WIP: core --- .../calcite/adapter/clone/ArrayTable.java | 46 +- .../calcite/adapter/clone/ColumnLoader.java | 13 +- .../adapter/enumerable/AggResultContext.java | 4 +- .../calcite/adapter/enumerable/EnumUtils.java | 150 +++--- .../enumerable/EnumerableAggregate.java | 13 +- .../enumerable/EnumerableAggregateBase.java | 15 +- .../enumerable/EnumerableAggregateRule.java | 4 +- .../enumerable/EnumerableBindable.java | 8 +- .../enumerable/EnumerableConvention.java | 8 +- .../enumerable/EnumerableInterpretable.java | 20 +- .../enumerable/EnumerableIntersect.java | 4 +- .../adapter/enumerable/EnumerableMatch.java | 14 +- .../enumerable/EnumerableMergeJoin.java | 34 +- .../enumerable/EnumerableMergeJoinRule.java | 4 +- .../adapter/enumerable/EnumerableMinus.java | 5 +- .../enumerable/EnumerableRelFactories.java | 2 +- .../enumerable/EnumerableRelImplementor.java | 5 +- .../enumerable/EnumerableSortRule.java | 4 +- .../enumerable/EnumerableSortedAggregate.java | 11 +- .../EnumerableSortedAggregateRule.java | 4 +- .../EnumerableTableFunctionScan.java | 4 +- .../enumerable/EnumerableTableModify.java | 6 +- .../enumerable/EnumerableTableScan.java | 15 +- .../enumerable/EnumerableTableScanRule.java | 4 +- .../enumerable/EnumerableTraitsUtils.java | 9 +- .../adapter/enumerable/EnumerableUnion.java | 4 +- .../adapter/enumerable/EnumerableValues.java | 8 +- .../adapter/enumerable/EnumerableWindow.java | 43 +- .../calcite/adapter/enumerable/PhysType.java | 6 +- .../adapter/enumerable/PhysTypeImpl.java | 12 +- .../adapter/enumerable/RexImpTable.java | 65 +-- .../enumerable/RexToLixTranslator.java | 85 ++-- .../enumerable/StrictAggImplementor.java | 5 +- .../enumerable/impl/AggResultContextImpl.java | 27 +- .../adapter/java/ReflectiveSchema.java | 26 +- .../adapter/jdbc/JdbcCatalogSchema.java | 20 +- .../adapter/jdbc/JdbcQueryProvider.java | 4 +- .../calcite/adapter/jdbc/JdbcRules.java | 17 +- .../calcite/adapter/jdbc/JdbcSchema.java | 14 +- .../calcite/adapter/jdbc/JdbcTable.java | 25 +- .../calcite/adapter/jdbc/JdbcTableScan.java | 4 +- .../calcite/adapter/jdbc/JdbcUtils.java | 30 +- .../config/CalciteConnectionConfig.java | 3 +- .../config/CalciteConnectionConfigImpl.java | 3 +- .../calcite/config/CalciteSystemProperty.java | 7 +- .../calcite/interpreter/AggregateNode.java | 38 +- .../apache/calcite/interpreter/Bindables.java | 26 +- .../interpreter/InterpretableConverter.java | 4 +- .../calcite/interpreter/Interpreter.java | 41 +- .../calcite/interpreter/Interpreters.java | 4 +- .../apache/calcite/interpreter/JoinNode.java | 16 +- .../apache/calcite/interpreter/SortNode.java | 12 +- .../calcite/interpreter/TableScanNode.java | 11 +- .../calcite/interpreter/ValuesNode.java | 5 +- .../calcite/jdbc/CachingCalciteSchema.java | 7 +- .../calcite/jdbc/CalciteConnectionImpl.java | 18 +- .../calcite/jdbc/CalciteJdbc41Factory.java | 30 +- .../apache/calcite/jdbc/CalciteMetaImpl.java | 15 +- .../apache/calcite/jdbc/CalcitePrepare.java | 2 +- .../apache/calcite/jdbc/CalciteSchema.java | 4 +- .../java/org/apache/calcite/jdbc/Driver.java | 11 +- .../apache/calcite/jdbc/JavaCollation.java | 2 +- .../apache/calcite/jdbc/JavaRecordType.java | 2 +- .../calcite/jdbc/JavaTypeFactoryImpl.java | 2 +- .../materialize/MaterializationActor.java | 10 +- .../materialize/MaterializationService.java | 38 +- .../org/apache/calcite/model/JsonColumn.java | 12 +- .../calcite/model/JsonCustomSchema.java | 25 +- .../apache/calcite/model/JsonCustomTable.java | 23 +- .../apache/calcite/model/JsonFunction.java | 27 +- .../apache/calcite/model/JsonJdbcSchema.java | 48 +- .../org/apache/calcite/model/JsonLattice.java | 61 ++- .../apache/calcite/model/JsonMapSchema.java | 14 + .../calcite/model/JsonMaterialization.java | 27 +- .../org/apache/calcite/model/JsonMeasure.java | 19 +- .../org/apache/calcite/model/JsonRoot.java | 17 +- .../org/apache/calcite/model/JsonSchema.java | 16 +- .../org/apache/calcite/model/JsonStream.java | 17 +- .../org/apache/calcite/model/JsonTable.java | 13 +- .../org/apache/calcite/model/JsonTile.java | 14 +- .../org/apache/calcite/model/JsonType.java | 18 +- .../calcite/model/JsonTypeAttribute.java | 17 +- .../org/apache/calcite/model/JsonView.java | 23 +- .../apache/calcite/model/ModelHandler.java | 111 ++--- .../org/apache/calcite/plan/Contexts.java | 6 +- .../calcite/plan/ConventionTraitDef.java | 8 +- .../calcite/plan/RelOptAbstractTable.java | 10 +- .../calcite/plan/RelOptPredicateList.java | 17 + .../org/apache/calcite/plan/RelOptTable.java | 10 +- .../org/apache/calcite/plan/RelOptUtil.java | 6 +- .../java/org/apache/calcite/plan/RelRule.java | 2 +- .../org/apache/calcite/plan/RelTraitSet.java | 2 +- .../calcite/plan/RexImplicationChecker.java | 28 +- .../calcite/plan/SubstitutionVisitor.java | 45 +- .../calcite/plan/VisitorDataContext.java | 33 +- .../apache/calcite/plan/hep/HepPlanner.java | 63 ++- .../plan/hep/HepRelMetadataProvider.java | 13 +- .../apache/calcite/plan/volcano/Dumpers.java | 10 +- .../plan/volcano/IterativeRuleDriver.java | 5 +- .../plan/volcano/TopDownRuleDriver.java | 39 +- .../volcano/VolcanoRelMetadataProvider.java | 13 +- .../calcite/prepare/CalciteCatalogReader.java | 2 +- .../calcite/prepare/CalciteMaterializer.java | 13 +- .../calcite/prepare/CalcitePrepareImpl.java | 24 +- .../calcite/prepare/LixToRelTranslator.java | 51 +- .../apache/calcite/prepare/PlannerImpl.java | 41 +- .../org/apache/calcite/prepare/Prepare.java | 25 +- .../calcite/prepare/QueryableRelBuilder.java | 13 +- .../calcite/prepare/RelOptTableImpl.java | 57 ++- .../apache/calcite/profile/ProfilerImpl.java | 2 +- .../java/org/apache/calcite/rel/RelInput.java | 20 +- .../java/org/apache/calcite/rel/RelNode.java | 2 + .../calcite/rel/convert/ConverterRule.java | 2 +- .../org/apache/calcite/rel/core/Collect.java | 4 +- .../apache/calcite/rel/core/Correlate.java | 20 +- .../org/apache/calcite/rel/core/Filter.java | 9 +- .../org/apache/calcite/rel/core/Project.java | 4 +- .../org/apache/calcite/rel/core/Sample.java | 4 +- .../calcite/rel/core/TableFunctionScan.java | 5 +- .../apache/calcite/rel/core/TableModify.java | 21 +- .../apache/calcite/rel/core/TableScan.java | 6 +- .../apache/calcite/rel/core/Uncollect.java | 6 +- .../calcite/rel/externalize/RelDotWriter.java | 9 +- .../calcite/rel/externalize/RelJson.java | 107 +++-- .../rel/externalize/RelJsonReader.java | 69 +-- .../calcite/rel/externalize/RelXmlWriter.java | 7 +- .../calcite/rel/hint/HintStrategyTable.java | 1 + .../calcite/rel/logical/LogicalCorrelate.java | 7 +- .../calcite/rel/logical/LogicalJoin.java | 10 +- .../calcite/rel/metadata/BuiltInMetadata.java | 4 +- .../metadata/CachingRelMetadataProvider.java | 2 +- .../metadata/ChainedRelMetadataProvider.java | 4 +- .../metadata/JaninoRelMetadataProvider.java | 2 +- .../calcite/rel/metadata/MetadataFactory.java | 4 +- .../rel/metadata/MetadataFactoryImpl.java | 20 +- .../ReflectiveRelMetadataProvider.java | 4 +- .../calcite/rel/metadata/RelMdCollation.java | 81 ++-- .../rel/metadata/RelMdColumnUniqueness.java | 2 +- .../rel/metadata/RelMdDistinctRowCount.java | 2 +- .../rel/metadata/RelMdDistribution.java | 6 +- .../rel/metadata/RelMdExplainVisibility.java | 4 +- .../rel/metadata/RelMdExpressionLineage.java | 6 +- .../rel/metadata/RelMdLowerBoundCost.java | 6 +- .../rel/metadata/RelMdMaxRowCount.java | 2 +- .../calcite/rel/metadata/RelMdMemory.java | 8 +- .../rel/metadata/RelMdPopulationSize.java | 20 +- .../calcite/rel/metadata/RelMdPredicates.java | 20 +- .../rel/metadata/RelMdSelectivity.java | 34 +- .../calcite/rel/metadata/RelMdSize.java | 36 +- .../calcite/rel/metadata/RelMdUtil.java | 2 +- .../rel/metadata/RelMetadataProvider.java | 2 +- .../rel/metadata/RelMetadataQuery.java | 7 +- .../rel/rel2sql/RelToSqlConverter.java | 3 +- .../calcite/rel/rel2sql/SqlImplementor.java | 13 +- .../AggregateProjectPullUpConstantsRule.java | 2 +- .../rel/rules/AggregateStarTableRule.java | 4 +- .../rules/ExchangeRemoveConstantKeysRule.java | 4 +- .../rel/rules/JoinToMultiJoinRule.java | 16 +- .../calcite/rel/rules/LoptMultiJoin.java | 40 +- .../rel/rules/LoptSemiJoinOptimizer.java | 10 +- .../calcite/rel/rules/ReduceDecimalsRule.java | 2 +- .../rel/rules/ReduceExpressionsRule.java | 4 +- .../rel/rules/SortRemoveConstantKeysRule.java | 2 +- .../rel/rules/UnionPullUpConstantsRule.java | 2 +- .../MaterializedViewAggregateRule.java | 4 +- .../rel/type/DynamicRecordTypeImpl.java | 4 +- .../rel/type/RelDataTypeFactoryImpl.java | 21 +- .../calcite/rel/type/RelDataTypeImpl.java | 10 +- .../org/apache/calcite/rex/LogicVisitor.java | 4 +- .../org/apache/calcite/rex/RexBuilder.java | 2 +- .../apache/calcite/rex/RexCallBinding.java | 2 +- .../org/apache/calcite/rex/RexChecker.java | 7 +- .../apache/calcite/rex/RexExecutorImpl.java | 4 +- .../org/apache/calcite/rex/RexLiteral.java | 2 +- .../org/apache/calcite/rex/RexNormalize.java | 2 +- .../org/apache/calcite/rex/RexProgram.java | 6 +- .../apache/calcite/rex/RexProgramBuilder.java | 7 +- .../rex/RexSqlReflectiveConvertletTable.java | 2 +- .../rex/RexSqlStandardConvertletTable.java | 5 +- .../apache/calcite/rex/RexUnaryBiVisitor.java | 4 +- .../java/org/apache/calcite/rex/RexUtil.java | 44 +- .../apache/calcite/rex/RexWindowBound.java | 3 + .../apache/calcite/runtime/ArrayBindable.java | 4 +- .../runtime/ArrayEnumeratorCursor.java | 6 +- .../org/apache/calcite/runtime/ConsList.java | 8 +- .../apache/calcite/runtime/Enumerables.java | 8 +- .../org/apache/calcite/runtime/FlatLists.java | 24 +- .../apache/calcite/runtime/JsonFunctions.java | 24 +- .../calcite/runtime/ResultSetEnumerable.java | 1 + .../apache/calcite/runtime/SqlFunctions.java | 16 +- .../runtime/TrustAllSslSocketFactory.java | 13 +- .../apache/calcite/runtime/XmlFunctions.java | 13 +- .../calcite/schema/FilterableTable.java | 4 +- .../calcite/schema/ModifiableTable.java | 2 +- .../java/org/apache/calcite/schema/Path.java | 6 +- .../schema/ProjectableFilterableTable.java | 2 +- .../apache/calcite/schema/ScannableTable.java | 4 +- .../org/apache/calcite/schema/Schema.java | 2 +- .../org/apache/calcite/schema/SchemaPlus.java | 2 +- .../org/apache/calcite/schema/Schemas.java | 73 +-- .../org/apache/calcite/schema/Statistic.java | 2 +- .../org/apache/calcite/schema/Statistics.java | 20 +- .../apache/calcite/schema/TableFactory.java | 5 +- .../org/apache/calcite/schema/Wrapper.java | 14 +- .../calcite/schema/impl/AbstractSchema.java | 14 +- .../calcite/schema/impl/AbstractTable.java | 2 +- .../calcite/schema/impl/DelegatingSchema.java | 2 +- .../schema/impl/ListTransientTable.java | 19 +- .../schema/impl/MaterializedViewTable.java | 11 +- .../schema/impl/ModifiableViewTable.java | 20 +- .../schema/impl/ScalarFunctionImpl.java | 4 +- .../schema/impl/TableFunctionImpl.java | 12 +- .../calcite/schema/impl/TableMacroImpl.java | 7 +- .../calcite/schema/impl/ViewTableMacro.java | 4 +- .../server/CalciteServerStatement.java | 6 +- .../calcite/server/DdlExecutorImpl.java | 2 +- .../apache/calcite/sql/SqlAggFunction.java | 2 +- .../calcite/sql/SqlBasicTypeNameSpec.java | 7 +- .../apache/calcite/sql/SqlBinaryOperator.java | 3 - .../java/org/apache/calcite/sql/SqlCall.java | 4 +- .../apache/calcite/sql/SqlCallBinding.java | 10 +- .../org/apache/calcite/sql/SqlDialect.java | 6 +- .../org/apache/calcite/sql/SqlExplain.java | 13 +- .../org/apache/calcite/sql/SqlFunction.java | 5 +- .../calcite/sql/SqlGroupedWindowFunction.java | 6 +- .../calcite/sql/SqlJdbcFunctionCall.java | 2 +- .../java/org/apache/calcite/sql/SqlJoin.java | 12 +- .../org/apache/calcite/sql/SqlLiteral.java | 12 +- .../org/apache/calcite/sql/SqlNodeList.java | 12 +- .../apache/calcite/sql/SqlNumericLiteral.java | 11 +- .../org/apache/calcite/sql/SqlOperator.java | 2 +- .../calcite/sql/SqlOperatorBinding.java | 2 +- .../java/org/apache/calcite/sql/SqlPivot.java | 10 +- .../apache/calcite/sql/SqlPrefixOperator.java | 12 +- .../calcite/sql/SqlRowTypeNameSpec.java | 3 +- .../java/org/apache/calcite/sql/SqlUtil.java | 4 +- .../apache/calcite/sql/advise/SqlAdvisor.java | 18 +- .../sql/dialect/BigQuerySqlDialect.java | 9 +- .../sql/dialect/ClickHouseSqlDialect.java | 6 +- .../calcite/sql/dialect/Db2SqlDialect.java | 2 +- .../calcite/sql/dialect/HiveSqlDialect.java | 4 +- .../calcite/sql/dialect/HsqldbSqlDialect.java | 6 +- .../calcite/sql/dialect/MssqlSqlDialect.java | 8 +- .../calcite/sql/dialect/MysqlSqlDialect.java | 6 +- .../calcite/sql/dialect/PrestoSqlDialect.java | 4 +- .../sql/dialect/RedshiftSqlDialect.java | 6 +- .../calcite/sql/dialect/SparkSqlDialect.java | 6 +- .../calcite/sql/dialect/SybaseSqlDialect.java | 4 +- .../sql/fun/SqlArrayValueConstructor.java | 6 +- .../calcite/sql/fun/SqlBetweenOperator.java | 5 +- .../calcite/sql/fun/SqlBitOpAggFunction.java | 2 +- .../org/apache/calcite/sql/fun/SqlCase.java | 1 + .../calcite/sql/fun/SqlCaseOperator.java | 4 +- .../calcite/sql/fun/SqlCastFunction.java | 4 +- .../calcite/sql/fun/SqlConvertFunction.java | 4 +- .../calcite/sql/fun/SqlCountAggFunction.java | 2 +- .../calcite/sql/fun/SqlExtractFunction.java | 8 +- .../calcite/sql/fun/SqlFloorFunction.java | 3 +- .../calcite/sql/fun/SqlGeoFunctions.java | 2 +- .../calcite/sql/fun/SqlJsonValueFunction.java | 2 +- .../calcite/sql/fun/SqlLibraryOperators.java | 2 +- .../sql/fun/SqlLiteralChainOperator.java | 3 +- .../sql/fun/SqlMapValueConstructor.java | 17 +- .../calcite/sql/fun/SqlMinMaxAggFunction.java | 2 +- .../sql/fun/SqlMonotonicBinaryOperator.java | 4 - .../sql/fun/SqlMultisetQueryConstructor.java | 10 +- .../sql/fun/SqlMultisetValueConstructor.java | 6 +- .../calcite/sql/fun/SqlOverlayFunction.java | 4 +- .../calcite/sql/fun/SqlSumAggFunction.java | 2 +- .../sql/fun/SqlSumEmptyIsZeroAggFunction.java | 2 +- .../calcite/sql/parser/SqlParserPos.java | 4 +- .../calcite/sql/pretty/SqlPrettyWriter.java | 34 +- .../sql/type/CursorReturnTypeInference.java | 4 +- .../sql/type/NonNullableAccessors.java | 50 ++ .../apache/calcite/sql/type/OperandTypes.java | 2 +- .../apache/calcite/sql/type/ReturnTypes.java | 19 +- .../sql/type/SameOperandTypeChecker.java | 4 +- ...meOperandTypeExceptLastOperandChecker.java | 8 +- .../calcite/sql/type/SqlTypeFactoryImpl.java | 3 +- .../apache/calcite/sql/type/SqlTypeName.java | 2 +- .../calcite/sql/type/SqlTypeTransforms.java | 20 +- .../apache/calcite/sql/type/SqlTypeUtil.java | 18 +- .../apache/calcite/sql/util/SqlShuttle.java | 8 +- .../sql/validate/AbstractNamespace.java | 2 +- .../sql/validate/DelegatingNamespace.java | 2 +- .../DelegatingSqlValidatorCatalogReader.java | 4 +- .../calcite/sql/validate/FieldNamespace.java | 6 +- .../calcite/sql/validate/JoinNamespace.java | 4 +- .../calcite/sql/validate/ListScope.java | 18 +- .../sql/validate/MatchRecognizeNamespace.java | 4 +- .../calcite/sql/validate/PivotNamespace.java | 4 +- .../calcite/sql/validate/PivotScope.java | 6 +- .../sql/validate/ProcedureNamespace.java | 6 +- .../calcite/sql/validate/SetopNamespace.java | 3 +- .../sql/validate/SqlNonNullableAccessors.java | 90 ++++ .../sql/validate/SqlScopedShuttle.java | 12 +- .../calcite/sql/validate/SqlValidator.java | 10 +- .../validate/SqlValidatorCatalogReader.java | 1 + .../sql/validate/SqlValidatorImpl.java | 441 +++++++++++------- .../sql/validate/SqlValidatorNamespace.java | 2 +- .../sql/validate/SqlValidatorUtil.java | 33 +- .../sql/validate/WithItemNamespace.java | 4 +- .../implicit/AbstractTypeCoercion.java | 17 +- .../sql/validate/implicit/TypeCoercion.java | 4 +- .../validate/implicit/TypeCoercionImpl.java | 22 +- .../NullInitializerExpressionFactory.java | 5 +- .../sql2rel/ReflectiveConvertletTable.java | 13 +- .../sql2rel/RelStructuredTypeFlattener.java | 18 +- .../sql2rel/SqlRexConvertletTable.java | 4 +- .../calcite/sql2rel/SqlToRelConverter.java | 99 ++-- .../sql2rel/StandardConvertletTable.java | 4 +- .../apache/calcite/tools/FrameworkConfig.java | 2 +- .../org/apache/calcite/tools/Frameworks.java | 2 +- .../java/org/apache/calcite/tools/Hoist.java | 4 +- .../apache/calcite/tools/PigRelBuilder.java | 7 +- .../org/apache/calcite/tools/Programs.java | 5 +- .../org/apache/calcite/tools/RelBuilder.java | 43 +- .../util/BarfingInvocationHandler.java | 6 +- .../java/org/apache/calcite/util/BitSets.java | 7 +- .../org/apache/calcite/util/BlackholeMap.java | 6 +- .../org/apache/calcite/util/CastingList.java | 10 +- .../org/apache/calcite/util/ChunkList.java | 42 +- .../org/apache/calcite/util/CompositeMap.java | 10 +- .../apache/calcite/util/ConversionUtil.java | 4 +- .../util/DelegatingInvocationHandler.java | 4 +- .../apache/calcite/util/EquivalenceSet.java | 4 +- .../org/apache/calcite/util/Filterator.java | 12 +- .../apache/calcite/util/ImmutableBeans.java | 29 +- .../apache/calcite/util/ImmutableBitSet.java | 21 +- .../apache/calcite/util/ImmutableIntList.java | 4 +- .../calcite/util/ImmutableNullableMap.java | 15 +- .../calcite/util/ImmutableNullableSet.java | 13 +- .../java/org/apache/calcite/util/Pair.java | 11 +- .../calcite/util/PartiallyOrderedSet.java | 40 +- .../calcite/util/RelToSqlConverterUtil.java | 9 +- .../calcite/util/SerializableCharset.java | 9 +- .../calcite/util/SimpleNamespaceContext.java | 1 + .../org/apache/calcite/util/Template.java | 6 +- .../java/org/apache/calcite/util/Util.java | 18 +- .../org/apache/calcite/util/XmlOutput.java | 15 +- .../org/apache/calcite/util/graph/Graphs.java | 7 +- .../util/graph/TopologicalOrderIterator.java | 25 +- .../calcite/util/javac/JaninoCompiler.java | 45 +- .../calcite/util/javac/JavaCompilerArgs.java | 5 +- .../calcite/util/trace/CalciteLogger.java | 35 +- .../calcite/adapter/generate/RangeTable.java | 4 +- .../rel2sql/RelToSqlConverterStructsTest.java | 7 +- .../calcite/schemas/HrClusteredSchema.java | 4 +- .../calcite/test/CollectionTypeTest.java | 13 +- .../calcite/test/CountriesTableFunction.java | 6 +- .../org/apache/calcite/test/JdbcTest.java | 3 +- .../org/apache/calcite/test/ModelTest.java | 15 +- .../calcite/test/ScannableTableTest.java | 10 +- .../calcite/test/SqlJsonFunctionsTest.java | 5 + .../calcite/test/StatesTableFunction.java | 6 +- .../org/apache/calcite/test/StreamTest.java | 23 +- .../test/catalog/MockCatalogReader.java | 6 +- .../apache/calcite/tools/FrameworksTest.java | 2 +- .../java/org/apache/calcite/util/Smalls.java | 8 +- .../calcite/adapter/druid/DruidQuery.java | 2 +- .../calcite/adapter/druid/DruidTable.java | 3 +- .../adapter/druid/DruidTableFactory.java | 3 +- .../adapter/csv/CsvFilterableTable.java | 18 +- .../adapter/csv/CsvScannableTable.java | 14 +- .../adapter/csv/CsvStreamScannableTable.java | 14 +- .../adapter/csv/CsvStreamTableFactory.java | 4 +- .../apache/calcite/adapter/csv/CsvTable.java | 10 +- .../calcite/adapter/csv/CsvTableFactory.java | 4 +- .../adapter/csv/CsvTranslatableTable.java | 6 +- .../calcite/example/maze/MazeTable.java | 8 +- .../calcite/adapter/file/CsvEnumerator.java | 36 +- .../calcite/adapter/file/CsvFieldType.java | 6 +- .../calcite/adapter/file/CsvTableFactory.java | 4 +- .../adapter/file/CsvTranslatableTable.java | 6 +- .../calcite/adapter/file/JsonEnumerator.java | 10 +- .../adapter/file/JsonScannableTable.java | 14 +- .../calcite/adapter/file/JsonTable.java | 6 +- .../simple/GeodeSimpleScannableTable.java | 12 +- gradle.properties | 1 - .../adapter/kafka/KafkaMessageEnumerator.java | 10 +- .../adapter/kafka/KafkaStreamTable.java | 12 +- .../adapter/kafka/KafkaTableFactory.java | 4 +- .../org/apache/calcite/linq4j/Linq4j.java | 4 +- .../calcite/linq4j/TransformedEnumerator.java | 4 +- .../calcite/linq4j/function/Functions.java | 8 +- .../calcite/linq4j/tree/Expressions.java | 2 +- .../apache/calcite/linq4j/tree/Primitive.java | 22 + .../calcite/adapter/pig/PigTableFactory.java | 4 +- .../org/apache/calcite/piglet/PigTable.java | 4 +- .../calcite/adapter/os/DuTableFunction.java | 6 +- .../adapter/os/FilesTableFunction.java | 30 +- .../adapter/os/GitCommitsTableFunction.java | 16 +- .../calcite/adapter/os/JpsTableFunction.java | 6 +- .../calcite/adapter/os/PsTableFunction.java | 12 +- .../adapter/os/StdinTableFunction.java | 6 +- .../adapter/os/VmstatTableFunction.java | 12 +- .../calcite/adapter/tpcds/TpcdsSchema.java | 20 +- .../chinook/PreferredAlbumsTableFactory.java | 4 +- .../chinook/PreferredGenresTableFactory.java | 4 +- .../calcite/adapter/redis/RedisTable.java | 4 +- .../adapter/redis/RedisTableFactory.java | 4 +- 401 files changed, 3565 insertions(+), 2062 deletions(-) create mode 100644 core/src/main/java/org/apache/calcite/sql/type/NonNullableAccessors.java create mode 100644 core/src/main/java/org/apache/calcite/sql/validate/SqlNonNullableAccessors.java diff --git a/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java b/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java index db045dbf632d..c9f97493cb8c 100644 --- a/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java +++ b/core/src/main/java/org/apache/calcite/adapter/clone/ArrayTable.java @@ -41,6 +41,8 @@ import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.reflect.Array; import java.lang.reflect.Type; import java.util.AbstractList; @@ -82,9 +84,9 @@ class ArrayTable extends AbstractQueryableTable implements ScannableTable { return Statistics.of(content.size, keys, content.collations); } - @Override public Enumerable scan(DataContext root) { - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { final Content content = supplier.get(); return content.arrayEnumerator(); } @@ -225,7 +227,7 @@ public static List asList(final Representation representation, // Cache size. It might be expensive to compute. final int size = representation.size(dataSet); return new AbstractList() { - @Override public Object get(int index) { + @Override public @Nullable Object get(int index) { return representation.getObject(dataSet, index); } @@ -243,9 +245,9 @@ public interface Representation { /** Converts a value set into a compact representation. If * {@code sources} is not null, permutes. */ - Object freeze(ColumnLoader.ValueSet valueSet, int[] sources); + Object freeze(ColumnLoader.ValueSet valueSet, int @Nullable [] sources); - Object getObject(Object dataSet, int ordinal); + @Nullable Object getObject(Object dataSet, int ordinal); int getInt(Object dataSet, int ordinal); /** Creates a data set that is the same as a given data set @@ -277,7 +279,7 @@ public static class ObjectArray implements Representation { return RepresentationType.OBJECT_ARRAY; } - @Override public Object freeze(ColumnLoader.ValueSet valueSet, int[] sources) { + @Override public Object freeze(ColumnLoader.ValueSet valueSet, int @Nullable [] sources) { // We assume the values have been canonized. final List list = permuteList(valueSet.values, sources); return list.toArray(new Comparable[0]); @@ -334,7 +336,7 @@ public static class PrimitiveArray implements Representation { return RepresentationType.PRIMITIVE_ARRAY; } - @Override public Object freeze(ColumnLoader.ValueSet valueSet, int[] sources) { + @Override public Object freeze(ColumnLoader.ValueSet valueSet, int @Nullable [] sources) { //noinspection unchecked return primitive.toArray2( permuteList((List) valueSet.values, sources)); @@ -344,7 +346,7 @@ public static class PrimitiveArray implements Representation { return primitive.permute(dataSet, sources); } - @Override public Object getObject(Object dataSet, int ordinal) { + @Override public @Nullable Object getObject(Object dataSet, int ordinal) { return p.arrayItem(dataSet, ordinal); } @@ -375,7 +377,7 @@ public static class PrimitiveDictionary implements Representation { return RepresentationType.PRIMITIVE_DICTIONARY; } - @Override public Object freeze(ColumnLoader.ValueSet valueSet, int[] sources) { + @Override public Object freeze(ColumnLoader.ValueSet valueSet, int @Nullable [] sources) { throw new UnsupportedOperationException(); // TODO: } @@ -423,7 +425,7 @@ public static class ObjectDictionary implements Representation { return RepresentationType.OBJECT_DICTIONARY; } - @Override public Object freeze(ColumnLoader.ValueSet valueSet, int[] sources) { + @Override public Object freeze(ColumnLoader.ValueSet valueSet, int @Nullable [] sources) { final int n = valueSet.map.keySet().size(); int extra = valueSet.containsNull ? 1 : 0; Comparable[] codeValues = @@ -486,7 +488,7 @@ public static class StringDictionary implements Representation { return RepresentationType.STRING_DICTIONARY; } - @Override public Object freeze(ColumnLoader.ValueSet valueSet, int[] sources) { + @Override public Object freeze(ColumnLoader.ValueSet valueSet, int @Nullable [] sources) { throw new UnsupportedOperationException(); // TODO: } @@ -524,7 +526,7 @@ public static class ByteStringDictionary implements Representation { return RepresentationType.BYTE_STRING_DICTIONARY; } - @Override public Object freeze(ColumnLoader.ValueSet valueSet, int[] sources) { + @Override public Object freeze(ColumnLoader.ValueSet valueSet, int @Nullable [] sources) { throw new UnsupportedOperationException(); // TODO: } @@ -565,7 +567,7 @@ public static class Constant implements Representation { return RepresentationType.CONSTANT; } - @Override public Object freeze(ColumnLoader.ValueSet valueSet, int[] sources) { + @Override public Object freeze(ColumnLoader.ValueSet valueSet, int @Nullable [] sources) { final int size = valueSet.values.size(); return Pair.of(size == 0 ? null : valueSet.values.get(0), size); } @@ -626,7 +628,7 @@ public static class BitSlicedPrimitiveArray implements Representation { return RepresentationType.BIT_SLICED_PRIMITIVE_ARRAY; } - @Override public Object freeze(ColumnLoader.ValueSet valueSet, int[] sources) { + @Override public Object freeze(ColumnLoader.ValueSet valueSet, int @Nullable [] sources) { final int chunksPerWord = 64 / bitCount; final List valueList = permuteList(valueSet.values, sources); @@ -783,7 +785,7 @@ public static void orLong( } private static List permuteList( - final List list, final int[] sources) { + final List list, final int @Nullable [] sources) { if (sources == null) { return list; } @@ -828,13 +830,13 @@ public Enumerator enumerator() { } } - public Enumerator arrayEnumerator() { + public Enumerator<@Nullable Object[]> arrayEnumerator() { return new ArrayEnumerator(size, columns); } /** Enumerator over a table with a single column; each element * returned is an object. */ - private static class ObjectEnumerator implements Enumerator { + private static class ObjectEnumerator implements Enumerator<@Nullable Object> { final int rowCount; final Object dataSet; final Representation representation; @@ -846,7 +848,7 @@ private static class ObjectEnumerator implements Enumerator { this.representation = column.representation; } - @Override public Object current() { + @Override public @Nullable Object current() { return representation.getObject(dataSet, i); } @@ -864,7 +866,7 @@ private static class ObjectEnumerator implements Enumerator { /** Enumerator over a table with more than one column; each element * returned is an array. */ - private static class ArrayEnumerator implements Enumerator { + private static class ArrayEnumerator implements Enumerator<@Nullable Object[]> { final int rowCount; final List columns; int i = -1; @@ -874,8 +876,8 @@ private static class ArrayEnumerator implements Enumerator { this.columns = columns; } - @Override public Object[] current() { - Object[] objects = new Object[columns.size()]; + @Override public @Nullable Object[] current() { + @Nullable Object[] objects = new Object[columns.size()]; for (int j = 0; j < objects.length; j++) { final Column pair = columns.get(j); objects[j] = pair.representation.getObject(pair.dataSet, i); diff --git a/core/src/main/java/org/apache/calcite/adapter/clone/ColumnLoader.java b/core/src/main/java/org/apache/calcite/adapter/clone/ColumnLoader.java index 2d200ce3f514..1846b1a7cd98 100644 --- a/core/src/main/java/org/apache/calcite/adapter/clone/ColumnLoader.java +++ b/core/src/main/java/org/apache/calcite/adapter/clone/ColumnLoader.java @@ -232,14 +232,14 @@ private void load(final RelDataType elementType, * value needs to be converted to a {@link Long}. Similarly * {@link java.sql.Date} and {@link java.sql.Time} values to * {@link Integer}. */ - private static List wrap(ColumnMetaData.Rep rep, List list, + private static List wrap(ColumnMetaData.Rep rep, List list, RelDataType type) { switch (type.getSqlTypeName()) { case TIMESTAMP: switch (rep) { case OBJECT: case JAVA_SQL_TIMESTAMP: - return Util.transform(list, + return Util.transform((List<@Nullable Timestamp>) list, (Timestamp t) -> t == null ? null : t.getTime()); default: break; @@ -249,7 +249,7 @@ private static List wrap(ColumnMetaData.Rep rep, List list, switch (rep) { case OBJECT: case JAVA_SQL_TIME: - return Util.transform(list, (Time t) -> t == null + return Util.transform((List<@Nullable Time>) list, (Time t) -> t == null ? null : (int) (t.getTime() % DateTimeUtils.MILLIS_PER_DAY)); default: @@ -260,9 +260,10 @@ private static List wrap(ColumnMetaData.Rep rep, List list, switch (rep) { case OBJECT: case JAVA_SQL_DATE: - return Util.transform(list, (Date d) -> d == null - ? null - : (int) (d.getTime() / DateTimeUtils.MILLIS_PER_DAY)); + return Util.<@Nullable Date, @Nullable Integer>transform( + (List<@Nullable Date>) list, (Date d) -> d == null + ? null + : (int) (d.getTime() / DateTimeUtils.MILLIS_PER_DAY)); default: break; } diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/AggResultContext.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/AggResultContext.java index 4191e7e889c9..ab130a0e65eb 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/AggResultContext.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/AggResultContext.java @@ -19,6 +19,8 @@ import org.apache.calcite.linq4j.tree.Expression; import org.apache.calcite.rel.core.AggregateCall; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Information for a call to * {@link AggImplementor#implementResult(AggContext, AggResultContext)} @@ -32,7 +34,7 @@ public interface AggResultContext extends NestedBlockBuilder, AggResetContext { * accumulator were aggregated. Most aggregate functions depend on only the * accumulator, but quasi-aggregate functions such as GROUPING access at the * key. */ - Expression key(); + @Nullable Expression key(); /** Returns an expression that references the {@code i}th field of the key, * cast to the appropriate type. */ diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java index fb8a24899a00..1e8b8193cec7 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumUtils.java @@ -62,6 +62,7 @@ import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.math.BigDecimal; +import java.text.Collator; import java.util.AbstractList; import java.util.ArrayDeque; import java.util.ArrayList; @@ -71,7 +72,8 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Objects; + +import static java.util.Objects.requireNonNull; /** * Utilities for generating programs in the Enumerable (functional) @@ -133,7 +135,7 @@ static List fieldRowTypes( final int arg = argList.get(index); return arg < inputFields.size() ? inputFields.get(arg).getType() - : Objects.requireNonNull(extraInputs, "extraInputs") + : requireNonNull(extraInputs, "extraInputs") .get(arg - inputFields.size()).getType(); } @Override public int size() { @@ -190,12 +192,12 @@ static Expression joinSelector(JoinRelType joinType, PhysType physType, * stored as {@code Integer} type, {@code java.sql.Timestamp} is * stored as {@code Long} type. */ - static Expression toInternal(Expression operand, Type targetType) { + static Expression toInternal(Expression operand, @Nullable Type targetType) { return toInternal(operand, operand.getType(), targetType); } private static Expression toInternal(Expression operand, - Type fromType, Type targetType) { + Type fromType, @Nullable Type targetType) { if (fromType == java.sql.Date.class) { if (targetType == int.class) { return Expressions.call(BuiltInMethod.DATE_TO_INT.method, operand); @@ -297,7 +299,7 @@ static Type fromInternal(Type type) { return type; } - private static Type toInternal(RelDataType type) { + private static @Nullable Type toInternal(RelDataType type) { return toInternal(type, false); } @@ -313,7 +315,7 @@ private static Type toInternal(RelDataType type) { } } - static List internalTypes(List operandList) { + static List<@Nullable Type> internalTypes(List operandList) { return Util.transform(operandList, node -> toInternal(node.getType())); } @@ -364,13 +366,13 @@ public static Expression convert(Expression operand, Type fromType, // Generate "SqlFunctions.toShort(x)". return Expressions.call( SqlFunctions.class, - "to" + SqlFunctions.initcap(toPrimitive.primitiveName), + "to" + SqlFunctions.initcap(toPrimitive.getPrimitiveName()), operand); default: // Generate "Short.parseShort(x)". return Expressions.call( - toPrimitive.boxClass, - "parse" + SqlFunctions.initcap(toPrimitive.primitiveName), + toPrimitive.getBoxClass(), + "parse" + SqlFunctions.initcap(toPrimitive.getPrimitiveName()), operand); } } @@ -380,12 +382,12 @@ public static Expression convert(Expression operand, Type fromType, // Generate "SqlFunctions.toCharBoxed(x)". return Expressions.call( SqlFunctions.class, - "to" + SqlFunctions.initcap(toBox.primitiveName) + "Boxed", + "to" + SqlFunctions.initcap(toBox.getPrimitiveName()) + "Boxed", operand); default: // Generate "Short.valueOf(x)". return Expressions.call( - toBox.boxClass, + toBox.getBoxClass(), "valueOf", operand); } @@ -395,7 +397,7 @@ public static Expression convert(Expression operand, Type fromType, if (fromPrimitive != null) { // E.g. from "float" to "double" return Expressions.convert_( - operand, toPrimitive.primitiveClass); + operand, toPrimitive.getPrimitiveClass()); } if (fromNumber || fromBox == Primitive.CHAR) { // Generate "x.shortValue()". @@ -405,7 +407,7 @@ public static Expression convert(Expression operand, Type fromType, // Generate "SqlFunctions.toShort(x)" return Expressions.call( SqlFunctions.class, - "to" + SqlFunctions.initcap(toPrimitive.primitiveName), + "to" + SqlFunctions.initcap(toPrimitive.getPrimitiveName()), operand); } } else if (fromNumber && toBox != null) { @@ -438,7 +440,7 @@ public static Expression convert(Expression operand, Type fromType, // Convert it first and generate "Byte.valueOf((byte)x)" // Because there is no method "Byte.valueOf(int)" in Byte return Expressions.box( - Expressions.convert_(operand, toBox.primitiveClass), + Expressions.convert_(operand, toBox.getPrimitiveClass()), toBox); } // Convert datetime types to internal storage type: @@ -503,7 +505,7 @@ public static Expression convert(Expression operand, Type fromType, // E.g. from "int" to "String" // Generate "Integer.toString(x)" return Expressions.call( - fromPrimitive.boxClass, + fromPrimitive.getBoxClass(), "toString", operand); } @@ -548,7 +550,7 @@ public static Expression convert(Expression operand, Type fromType, } /** Converts a value to a given class. */ - public static T evaluate(Object o, Class clazz) { + public static @Nullable T evaluate(Object o, Class clazz) { // We need optimization here for constant folding. // Not all the expressions can be interpreted (e.g. ternary), so // we rely on optimization capabilities to fold non-interpretable @@ -559,7 +561,7 @@ public static T evaluate(Object o, Class clazz) { final Expression expr = convert(Expressions.constant(o), clazz); bb.add(Expressions.return_(null, expr)); - final FunctionExpression convert = + final FunctionExpression convert = Expressions.lambda(bb.toBlock(), ImmutableList.of()); return clazz.cast(convert.compile().dynamicInvoke()); } @@ -644,9 +646,9 @@ public static MethodCallExpression call(Class clazz, String methodName, * @return MethodCallExpression that call the given name method * @throws RuntimeException if no suitable method found */ - public static MethodCallExpression call(Class clazz, String methodName, + public static MethodCallExpression call(Class clazz, String methodName, List arguments, @Nullable Expression targetExpression) { - Class[] argumentTypes = Types.toClassArray(arguments); + Class[] argumentTypes = Types.toClassArray(arguments); try { Method candidate = clazz.getMethod(methodName, argumentTypes); return Expressions.call(targetExpression, candidate, arguments); @@ -654,7 +656,7 @@ public static MethodCallExpression call(Class clazz, String methodName, for (Method method : clazz.getMethods()) { if (method.getName().equals(methodName)) { final boolean varArgs = method.isVarArgs(); - final Class[] parameterTypes = method.getParameterTypes(); + final Class[] parameterTypes = method.getParameterTypes(); if (Types.allAssignable(varArgs, parameterTypes, argumentTypes)) { return Expressions.call(targetExpression, method, arguments); } @@ -672,14 +674,14 @@ public static MethodCallExpression call(Class clazz, String methodName, } private static @Nullable List matchMethodParameterTypes(boolean varArgs, - Class[] parameterTypes, List arguments) { + Class[] parameterTypes, List arguments) { if ((varArgs && arguments.size() < parameterTypes.length - 1) || (!varArgs && arguments.size() != parameterTypes.length)) { return null; } final List typeMatchedArguments = new ArrayList<>(); for (int i = 0; i < arguments.size(); i++) { - Class parameterType = + Class parameterType = !varArgs || i < parameterTypes.length - 1 ? parameterTypes[i] : Object.class; @@ -702,7 +704,7 @@ public static MethodCallExpression call(Class clazz, String methodName, * Returns null if it is impossible to match. */ private static @Nullable Expression matchMethodParameterType( - Expression argument, Class parameter) { + Expression argument, Class parameter) { Type argumentType = argument.getType(); if (Types.isAssignableFrom(parameter, argumentType)) { return argument; @@ -847,10 +849,11 @@ static Expression tumblingWindowSelector( * enumerator based on a specified key. Elements are windowed into sessions separated by * periods with no input for at least the duration specified by gap parameter. */ - public static Enumerable sessionize(Enumerator inputEnumerator, + public static Enumerable<@Nullable Object[]> sessionize( + Enumerator<@Nullable Object[]> inputEnumerator, int indexOfWatermarkedColumn, int indexOfKeyColumn, long gap) { - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { return new SessionizationEnumerator(inputEnumerator, indexOfWatermarkedColumn, indexOfKeyColumn, gap); } @@ -858,12 +861,12 @@ public static Enumerable sessionize(Enumerator inputEnumerat } /** Enumerator that converts rows into sessions separated by gaps. */ - private static class SessionizationEnumerator implements Enumerator { - private final Enumerator inputEnumerator; + private static class SessionizationEnumerator implements Enumerator<@Nullable Object[]> { + private final Enumerator<@Nullable Object[]> inputEnumerator; private final int indexOfWatermarkedColumn; private final int indexOfKeyColumn; private final long gap; - private final Deque list; + private final Deque<@Nullable Object[]> list; private boolean initialized; /** @@ -875,7 +878,7 @@ private static class SessionizationEnumerator implements Enumerator { * @param indexOfKeyColumn the index of column that acts as grouping key * @param gap gap parameter */ - SessionizationEnumerator(Enumerator inputEnumerator, + SessionizationEnumerator(Enumerator<@Nullable Object[]> inputEnumerator, int indexOfWatermarkedColumn, int indexOfKeyColumn, long gap) { this.inputEnumerator = inputEnumerator; this.indexOfWatermarkedColumn = indexOfWatermarkedColumn; @@ -885,12 +888,12 @@ private static class SessionizationEnumerator implements Enumerator { initialized = false; } - @Override public Object[] current() { + @Override public @Nullable Object[] current() { if (!initialized) { initialize(); initialized = true; } - return Objects.requireNonNull(list.pollFirst(), "list.pollFirst()"); + return list.removeFirst(); } @Override public boolean moveNext() { @@ -910,7 +913,7 @@ private static class SessionizationEnumerator implements Enumerator { } private void initialize() { - List elements = new ArrayList<>(); + List<@Nullable Object[]> elements = new ArrayList<>(); // initialize() will be called when inputEnumerator.moveNext() is true, // thus firstly should take the current element. elements.add(inputEnumerator.current()); @@ -919,21 +922,25 @@ private void initialize() { elements.add(inputEnumerator.current()); } - Map, Object[]>> sessionKeyMap = new HashMap<>(); - for (Object[] element : elements) { - sessionKeyMap.putIfAbsent(element[indexOfKeyColumn], new SortedMultiMap<>()); - Pair initWindow = computeInitWindow( - SqlFunctions.toLong(element[indexOfWatermarkedColumn]), gap); - sessionKeyMap.get(element[indexOfKeyColumn]).putMulti(initWindow, element); + Map<@Nullable Object, SortedMultiMap, @Nullable Object[]>> sessionKeyMap = + new HashMap<>(); + for (@Nullable Object[] element : elements) { + SortedMultiMap, @Nullable Object[]> session = + sessionKeyMap.computeIfAbsent(element[indexOfKeyColumn], k -> new SortedMultiMap<>()); + Object watermark = requireNonNull(element[indexOfWatermarkedColumn], + "element[indexOfWatermarkedColumn]"); + Pair initWindow = computeInitWindow( + SqlFunctions.toLong(watermark), gap); + session.putMulti(initWindow, element); } // merge per key session windows if there is any overlap between windows. - for (Map.Entry, Object[]>> perKeyEntry - : sessionKeyMap.entrySet()) { - Map, List> finalWindowElementsMap = new HashMap<>(); + for (Map.Entry<@Nullable Object, SortedMultiMap, @Nullable Object[]>> + perKeyEntry : sessionKeyMap.entrySet()) { + Map, List<@Nullable Object[]>> finalWindowElementsMap = new HashMap<>(); Pair currentWindow = null; - List tempElementList = new ArrayList<>(); - for (Map.Entry, List> sessionEntry + List<@Nullable Object[]> tempElementList = new ArrayList<>(); + for (Map.Entry, List<@Nullable Object[]>> sessionEntry : perKeyEntry.getValue().entrySet()) { // check the next window can be merged. if (currentWindow == null || !isOverlapped(currentWindow, sessionEntry.getKey())) { @@ -954,14 +961,15 @@ private void initialize() { } if (!tempElementList.isEmpty()) { + requireNonNull(currentWindow, "currentWindow is null"); finalWindowElementsMap.put(currentWindow, new ArrayList<>(tempElementList)); } // construct final results from finalWindowElementsMap. - for (Map.Entry, List> finalWindowElementsEntry + for (Map.Entry, List<@Nullable Object[]>> finalWindowElementsEntry : finalWindowElementsMap.entrySet()) { - for (Object[] element : finalWindowElementsEntry.getValue()) { - Object[] curWithWindow = new Object[element.length + 2]; + for (@Nullable Object[] element : finalWindowElementsEntry.getValue()) { + @Nullable Object[] curWithWindow = new Object[element.length + 2]; System.arraycopy(element, 0, curWithWindow, 0, element.length); curWithWindow[element.length] = finalWindowElementsEntry.getKey().left; curWithWindow[element.length + 1] = finalWindowElementsEntry.getKey().right; @@ -988,10 +996,11 @@ private Pair computeInitWindow(long ts, long gap) { * Create enumerable implementation that applies hopping on each element from the input * enumerator and produces at least one element for each input element. */ - public static Enumerable hopping(Enumerator inputEnumerator, + public static Enumerable<@Nullable Object[]> hopping( + Enumerator<@Nullable Object[]> inputEnumerator, int indexOfWatermarkedColumn, long emitFrequency, long windowSize, long offset) { - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { return new HopEnumerator(inputEnumerator, indexOfWatermarkedColumn, emitFrequency, windowSize, offset); } @@ -999,13 +1008,13 @@ public static Enumerable hopping(Enumerator inputEnumerator, } /** Enumerator that computes HOP. */ - private static class HopEnumerator implements Enumerator { - private final Enumerator inputEnumerator; + private static class HopEnumerator implements Enumerator<@Nullable Object[]> { + private final Enumerator<@Nullable Object[]> inputEnumerator; private final int indexOfWatermarkedColumn; private final long emitFrequency; private final long windowSize; private final long offset; - private final Deque list; + private final Deque<@Nullable Object[]> list; /** * Note that it only works for batch scenario. E.g. all data is known and there is no late data. @@ -1016,7 +1025,7 @@ private static class HopEnumerator implements Enumerator { * @param windowSize window size * @param offset indicates how much windows should off */ - HopEnumerator(Enumerator inputEnumerator, + HopEnumerator(Enumerator<@Nullable Object[]> inputEnumerator, int indexOfWatermarkedColumn, long slide, long windowSize, long offset) { this.inputEnumerator = inputEnumerator; this.indexOfWatermarkedColumn = indexOfWatermarkedColumn; @@ -1026,15 +1035,17 @@ private static class HopEnumerator implements Enumerator { list = new ArrayDeque<>(); } - @Override public Object[] current() { + @Override public @Nullable Object[] current() { if (list.size() > 0) { return takeOne(); } else { - Object[] current = inputEnumerator.current(); - List windows = hopWindows(SqlFunctions.toLong(current[indexOfWatermarkedColumn]), + @Nullable Object[] current = inputEnumerator.current(); + Object watermark = requireNonNull(current[indexOfWatermarkedColumn], + "element[indexOfWatermarkedColumn]"); + List> windows = hopWindows(SqlFunctions.toLong(watermark), emitFrequency, windowSize, offset); - for (Pair window : windows) { - Object[] curWithWindow = new Object[current.length + 2]; + for (Pair window : windows) { + @Nullable Object[] curWithWindow = new Object[current.length + 2]; System.arraycopy(current, 0, curWithWindow, 0, current.length); curWithWindow[current.length] = window.left; curWithWindow[current.length + 1] = window.right; @@ -1056,19 +1067,19 @@ private static class HopEnumerator implements Enumerator { @Override public void close() { } - private Object @Nullable [] takeOne() { - return Objects.requireNonNull(list.pollFirst(), "list.pollFirst()"); + private @Nullable Object[] takeOne() { + return requireNonNull(list.pollFirst(), "list.pollFirst()"); } } - private static List hopWindows( + private static List> hopWindows( long tsMillis, long periodMillis, long sizeMillis, long offsetMillis) { - ArrayList ret = new ArrayList<>(Math.toIntExact(sizeMillis / periodMillis)); + ArrayList> ret = new ArrayList<>(Math.toIntExact(sizeMillis / periodMillis)); long lastStart = tsMillis - ((tsMillis + periodMillis - offsetMillis) % periodMillis); for (long start = lastStart; start > tsMillis - sizeMillis; start -= periodMillis) { - ret.add(new Pair(start, start + sizeMillis)); + ret.add(new Pair<>(start, start + sizeMillis)); } return ret; } @@ -1084,7 +1095,7 @@ public static Enumerable tumbling( // exactly one element for each input element. @Override public Enumerator enumerator() { return new Enumerator() { - Enumerator inputs = inputEnumerable.enumerator(); + final Enumerator inputs = inputEnumerable.enumerator(); @Override public TResult current() { return outSelector.apply(inputs.current()); @@ -1099,6 +1110,7 @@ public static Enumerable tumbling( } @Override public void close() { + inputs.close(); } }; } @@ -1106,7 +1118,11 @@ public static Enumerable tumbling( } public static @Nullable Expression generateCollatorExpression(@Nullable SqlCollation collation) { - if (collation == null || collation.getCollator() == null) { + if (collation == null) { + return null; + } + Collator collator = collation.getCollator(); + if (collator == null) { return null; } @@ -1117,7 +1133,7 @@ public static Enumerable tumbling( // collation.getLocale().getVariant()), // collation.getCollator().getStrength()); final Locale locale = collation.getLocale(); - final int strength = collation.getCollator().getStrength(); + final int strength = collator.getStrength(); return Expressions.call( Utilities.class, "generateCollator", diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java index 5f7b73be4d69..14a9c8e0df46 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregate.java @@ -42,6 +42,8 @@ import java.util.ArrayList; import java.util.List; +import static java.util.Objects.requireNonNull; + /** Implementation of {@link org.apache.calcite.rel.core.Aggregate} in * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */ public class EnumerableAggregate extends EnumerableAggregateBase implements EnumerableRel { @@ -50,7 +52,7 @@ public EnumerableAggregate( RelTraitSet traitSet, RelNode input, ImmutableBitSet groupSet, - List groupSets, + @Nullable List groupSets, List aggCalls) throws InvalidRelException { super(cluster, traitSet, ImmutableList.of(), input, groupSet, groupSets, aggCalls); @@ -255,8 +257,9 @@ public EnumerableAggregate(RelOptCluster cluster, RelTraitSet traitSet, } for (final AggImpState agg : aggs) { results.add( - agg.implementor.implementResult(agg.context, - new AggResultContextImpl(resultBlock, agg.call, agg.state, key_, + agg.implementor.implementResult(requireNonNull(agg.context, "agg.context"), + new AggResultContextImpl(resultBlock, agg.call, + requireNonNull(agg.state, "agg.state"), key_, keyPhysType))); } resultBlock.add(physType.record(results)); @@ -275,7 +278,7 @@ public EnumerableAggregate(RelOptCluster cluster, RelTraitSet traitSet, builder.append("resultSelector", Expressions.lambda(Function2.class, resultBlock.toBlock(), - key_, + requireNonNull(key_, "key_"), acc_)); builder.add( Expressions.return_(null, @@ -337,7 +340,7 @@ public EnumerableAggregate(RelOptCluster cluster, RelTraitSet traitSet, builder.append("resultSelector", Expressions.lambda(Function2.class, resultBlock.toBlock(), - key_, + requireNonNull(key_, "key_"), acc_)); builder.add( Expressions.return_(null, diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateBase.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateBase.java index 24b20ea5a20a..4ce42218a753 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateBase.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateBase.java @@ -54,6 +54,8 @@ import java.util.LinkedList; import java.util.List; +import static java.util.Objects.requireNonNull; + /** Base class for EnumerableAggregate and EnumerableSortedAggregate. */ public abstract class EnumerableAggregateBase extends Aggregate { protected EnumerableAggregateBase( @@ -62,7 +64,7 @@ protected EnumerableAggregateBase( List hints, RelNode input, ImmutableBitSet groupSet, - List groupSets, + @Nullable List groupSets, List aggCalls) { super(cluster, traitSet, hints, input, groupSet, groupSets, aggCalls); } @@ -141,7 +143,7 @@ protected void implementLambdaFactory(BlockBuilder builder, Expressions.call(pe, BuiltInMethod.COLLECTION_ADD.method, Expressions.new_(BuiltInMethod.BASIC_LAZY_ACCUMULATOR.constructor, - agg.accumulatorAdder)))); + requireNonNull(agg.accumulatorAdder, "agg.accumulatorAdder"))))); continue; } final Pair pair = @@ -152,7 +154,8 @@ protected void implementLambdaFactory(BlockBuilder builder, Expressions.call(pe, BuiltInMethod.COLLECTION_ADD.method, Expressions.new_(BuiltInMethod.SOURCE_SORTER.constructor, - agg.accumulatorAdder, pair.left, pair.right)))); + requireNonNull(agg.accumulatorAdder, "agg.accumulatorAdder"), + pair.left, pair.right)))); } builder.add( Expressions.declare(0, lambdaFactory, @@ -170,7 +173,7 @@ protected void implementLambdaFactory(BlockBuilder builder, builder.add( Expressions.statement( Expressions.call(pe, BuiltInMethod.COLLECTION_ADD.method, - agg.accumulatorAdder))); + requireNonNull(agg.accumulatorAdder, "agg.accumulatorAdder")))); } builder.add( Expressions.declare(0, lambdaFactory, @@ -244,7 +247,7 @@ protected void createAccumulatorAdders( final BlockBuilder builder2 = new BlockBuilder(); final AggImpState agg = aggs.get(i); - final int stateSize = agg.state.size(); + final int stateSize = requireNonNull(agg.state, "agg.state").size(); final List accumulator = new ArrayList<>(stateSize); for (int j = 0; j < stateSize; j++) { accumulator.add(accPhysType.fieldReference(accExpr, j + stateOffset)); @@ -282,7 +285,7 @@ protected void createAccumulatorAdders( } }; - agg.implementor.implementAdd(agg.context, addContext); + agg.implementor.implementAdd(requireNonNull(agg.context, "agg.context"), addContext); builder2.add(accExpr); agg.accumulatorAdder = builder.append("accumulatorAdder", Expressions.lambda(Function2.class, builder2.toBlock(), accExpr, diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java index 78612aaba4ff..6e85a116f4af 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java @@ -23,6 +23,8 @@ import org.apache.calcite.rel.convert.ConverterRule; import org.apache.calcite.rel.logical.LogicalAggregate; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Rule to convert a {@link org.apache.calcite.rel.logical.LogicalAggregate} * to an {@link EnumerableAggregate}. @@ -41,7 +43,7 @@ protected EnumerableAggregateRule(Config config) { super(config); } - @Override public RelNode convert(RelNode rel) { + @Override public @Nullable RelNode convert(RelNode rel) { final LogicalAggregate agg = (LogicalAggregate) rel; final RelTraitSet traitSet = rel.getCluster() .traitSet().replace(EnumerableConvention.INSTANCE); diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBindable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBindable.java index 9ee7ec81aad8..0a04893de37c 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBindable.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableBindable.java @@ -35,6 +35,8 @@ import com.google.common.collect.ImmutableMap; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -59,7 +61,7 @@ protected EnumerableBindable(RelOptCluster cluster, RelNode input) { return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { final ImmutableMap map = ImmutableMap.of(); final Bindable bindable = EnumerableInterpretable.toBindable(map, null, (EnumerableRel) getInput(), EnumerableRel.Prefer.ARRAY); @@ -71,8 +73,8 @@ protected EnumerableBindable(RelOptCluster cluster, RelNode input) { return () -> { final Sink sink = implementor.relSinks.get(EnumerableBindable.this).get(0); - final Enumerable enumerable = bind(implementor.dataContext); - final Enumerator enumerator = enumerable.enumerator(); + final Enumerable<@Nullable Object[]> enumerable = bind(implementor.dataContext); + final Enumerator<@Nullable Object[]> enumerator = enumerable.enumerator(); while (enumerator.moveNext()) { sink.send(Row.asCopy(enumerator.current())); } diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java index 3cbffaf0c1ee..f2dcbc5e77bd 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableConvention.java @@ -28,6 +28,10 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.RelFactories; +import org.checkerframework.checker.nullness.qual.Nullable; + +import static java.util.Objects.requireNonNull; + /** * Family of calling conventions that return results as an * {@link org.apache.calcite.linq4j.Enumerable}. @@ -51,7 +55,7 @@ public enum EnumerableConvention implements Convention { return "ENUMERABLE"; } - @Override public RelNode enforce( + @Override public @Nullable RelNode enforce( final RelNode input, final RelTraitSet required) { RelNode rel = input; @@ -59,6 +63,8 @@ public enum EnumerableConvention implements Convention { rel = ConventionTraitDef.INSTANCE.convert( input.getCluster().getPlanner(), input, INSTANCE, true); + requireNonNull(rel, + () -> "Unable to convert input to " + INSTANCE + ", input = " + input); } RelCollation collation = required.getCollation(); if (collation != null && collation != RelCollations.EMPTY) { diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpretable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpretable.java index 8b18fba78ff0..616ef22f15eb 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpretable.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableInterpretable.java @@ -85,7 +85,7 @@ protected EnumerableInterpretable(RelOptCluster cluster, RelNode input) { implementor.spark, (EnumerableRel) getInput(), EnumerableRel.Prefer.ARRAY); final ArrayBindable arrayBindable = box(bindable); - final Enumerable enumerable = + final Enumerable<@Nullable Object[]> enumerable = arrayBindable.bind(implementor.dataContext); return new EnumerableNode(enumerable, implementor.compiler, this); } @@ -186,13 +186,13 @@ static ArrayBindable box(final Bindable bindable) { return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { final Enumerable enumerable = bindable.bind(dataContext); - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { final Enumerator enumerator = enumerable.enumerator(); - return new Enumerator() { - @Override public Object[] current() { + return new Enumerator<@Nullable Object[]>() { + @Override public @Nullable Object[] current() { return new Object[] {enumerator.current()}; } @@ -218,19 +218,19 @@ static ArrayBindable box(final Bindable bindable) { * *

From the interpreter's perspective, it is a leaf node. */ private static class EnumerableNode implements Node { - private final Enumerable enumerable; + private final Enumerable<@Nullable Object[]> enumerable; private final Sink sink; - EnumerableNode(Enumerable enumerable, Compiler compiler, + EnumerableNode(Enumerable<@Nullable Object[]> enumerable, Compiler compiler, EnumerableInterpretable rel) { this.enumerable = enumerable; this.sink = compiler.sink(rel); } @Override public void run() throws InterruptedException { - final Enumerator enumerator = enumerable.enumerator(); + final Enumerator<@Nullable Object[]> enumerator = enumerable.enumerator(); while (enumerator.moveNext()) { - Object[] values = enumerator.current(); + @Nullable Object[] values = enumerator.current(); sink.send(Row.of(values)); } } diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableIntersect.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableIntersect.java index ab95359709ec..e20a8ad765ea 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableIntersect.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableIntersect.java @@ -28,6 +28,8 @@ import java.util.List; +import static java.util.Objects.requireNonNull; + /** Implementation of {@link org.apache.calcite.rel.core.Intersect} in * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */ public class EnumerableIntersect extends Intersect implements EnumerableRel { @@ -68,7 +70,7 @@ public EnumerableIntersect(RelOptCluster cluster, RelTraitSet traitSet, pref = pref.of(result.format); } - builder.add(intersectExp); + builder.add(requireNonNull(intersectExp, "intersectExp")); final PhysType physType = PhysTypeImpl.of( implementor.getTypeFactory(), diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMatch.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMatch.java index 0e6d60d34ddb..13c39a1c7cd8 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMatch.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMatch.java @@ -99,7 +99,7 @@ public static EnumerableMatch create(RelNode input, RelDataType rowType, } @Override public RelNode copy(RelTraitSet traitSet, List inputs) { - return new EnumerableMatch(getCluster(), traitSet, inputs.get(0), rowType, + return new EnumerableMatch(getCluster(), traitSet, inputs.get(0), getRowType(), pattern, strictStart, strictEnd, patternDefinitions, measures, after, subsets, allRows, partitionKeys, orderKeys, interval); } @@ -454,7 +454,7 @@ public int getFuture() { * A special Getter that is able to return a field from a list of objects. */ static class PassedRowsInputGetter implements RexToLixTranslator.InputGetter { - private Expression index; + private @Nullable Expression index; private final ParameterExpression row; private final ParameterExpression passedRows; private final Function generator; @@ -470,12 +470,12 @@ static class PassedRowsInputGetter implements RexToLixTranslator.InputGetter { this.physType = physType; } - void setIndex(Expression index) { + void setIndex(@Nullable Expression index) { this.index = index; } @Override public Expression field(BlockBuilder list, int index, - Type storageType) { + @Nullable Type storageType) { if (this.index == null) { return generator.apply(this.row).field(list, index, storageType); } @@ -496,7 +496,7 @@ void setIndex(Expression index) { * A special Getter that "interchanges" the PREV and the field call. */ static class PrevInputGetter implements RexToLixTranslator.InputGetter { - private Expression offset; + private @Nullable Expression offset; private final ParameterExpression row; private final Function generator; private final PhysType physType; @@ -509,12 +509,12 @@ static class PrevInputGetter implements RexToLixTranslator.InputGetter { this.physType = physType; } - void setOffset(Expression offset) { + void setOffset(@Nullable Expression offset) { this.offset = offset; } @Override public Expression field(BlockBuilder list, int index, - Type storageType) { + @Nullable Type storageType) { final ParameterExpression row = Expressions.parameter(physType.getJavaRowType()); final ParameterExpression tmp = diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java index 28b4beb5f5ba..ca36252948d1 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoin.java @@ -61,6 +61,8 @@ import static org.apache.calcite.rel.RelCollations.containsOrderless; +import static java.util.Objects.requireNonNull; + /** Implementation of {@link org.apache.calcite.rel.core.Join} in * {@link EnumerableConvention enumerable calling convention} using * a merge algorithm. */ @@ -75,10 +77,8 @@ protected EnumerableMergeJoin( JoinRelType joinType) { super(cluster, traits, ImmutableList.of(), left, right, condition, variablesSet, joinType); assert getConvention() instanceof EnumerableConvention; - final List leftCollations = - left.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE); - final List rightCollations = - right.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE); + final List leftCollations = getCollations(left.getTraitSet()); + final List rightCollations = getCollations(right.getTraitSet()); // If the join keys are not distinct, the sanity check doesn't apply. // e.g. t1.a=t2.b and t1.a=t2.c @@ -120,6 +120,16 @@ public static boolean isMergeJoinSupported(JoinRelType joinType) { return EnumerableDefaults.isMergeJoinSupported(EnumUtils.toLinq4jJoinType(joinType)); } + private static RelCollation getCollation(RelTraitSet traits) { + return requireNonNull(traits.getCollation(), + () -> "no collation trait in " + traits); + } + + private static List getCollations(RelTraitSet traits) { + return requireNonNull(traits.getTraits(RelCollationTraitDef.INSTANCE), + () -> "no collation trait in " + traits); + } + @Deprecated // to be removed before 2.0 EnumerableMergeJoin(RelOptCluster cluster, RelTraitSet traits, RelNode left, RelNode right, RexNode condition, ImmutableIntList leftKeys, @@ -179,7 +189,7 @@ public static boolean isMergeJoinSupported(JoinRelType joinType) { @Override public @Nullable Pair> passThroughTraits( final RelTraitSet required) { // Required collation keys can be subset or superset of merge join keys. - RelCollation collation = required.getCollation(); + RelCollation collation = getCollation(required); int leftInputFieldCount = left.getRowType().getFieldCount(); List reqKeys = RelCollations.ordinals(collation); @@ -262,7 +272,7 @@ public static boolean isMergeJoinSupported(JoinRelType joinType) { @Override public @Nullable Pair> deriveTraits( final RelTraitSet childTraits, final int childId) { final int keyCount = joinInfo.leftKeys.size(); - RelCollation collation = childTraits.getCollation(); + RelCollation collation = getCollation(childTraits); final int colCount = collation.getFieldCollations().size(); if (colCount < keyCount || keyCount == 0) { return null; @@ -370,7 +380,7 @@ public static EnumerableMergeJoin create(RelNode left, RelNode right, final RelMetadataQuery mq = cluster.getMetadataQuery(); final List collations = RelMdCollation.mergeJoin(mq, left, right, leftKeys, rightKeys, joinType); - traitSet = traitSet.replace(collations); + traitSet = traitSet.replaceIfs(RelCollationTraitDef.INSTANCE, () -> collations); } return new EnumerableMergeJoin(cluster, traitSet, left, right, condition, ImmutableSet.of(), joinType); @@ -415,11 +425,11 @@ public static EnumerableMergeJoin create(RelNode left, RelNode right, final List leftExpressions = new ArrayList<>(); final List rightExpressions = new ArrayList<>(); for (Pair pair : Pair.zip(joinInfo.leftKeys, joinInfo.rightKeys)) { - final RelDataType keyType = - typeFactory.leastRestrictive( - ImmutableList.of( - left.getRowType().getFieldList().get(pair.left).getType(), - right.getRowType().getFieldList().get(pair.right).getType())); + RelDataType leftType = left.getRowType().getFieldList().get(pair.left).getType(); + RelDataType rightType = right.getRowType().getFieldList().get(pair.right).getType(); + final RelDataType keyType = requireNonNull( + typeFactory.leastRestrictive(ImmutableList.of(leftType, rightType)), + () -> "leastRestrictive returns null for " + leftType + " and " + rightType); final Type keyClass = typeFactory.getJavaClass(keyType); leftExpressions.add( EnumUtils.convert( diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoinRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoinRule.java index 0a0ad07908a3..36deb59d3b77 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoinRule.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoinRule.java @@ -31,6 +31,8 @@ import org.apache.calcite.rex.RexNode; import org.apache.calcite.rex.RexUtil; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -54,7 +56,7 @@ protected EnumerableMergeJoinRule(Config config) { super(config); } - @Override public RelNode convert(RelNode rel) { + @Override public @Nullable RelNode convert(RelNode rel) { LogicalJoin join = (LogicalJoin) rel; final JoinInfo info = join.analyzeCondition(); if (!EnumerableMergeJoin.isMergeJoinSupported(join.getJoinType())) { diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMinus.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMinus.java index 9b85a8a45b07..e9c45c9641b0 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMinus.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMinus.java @@ -28,6 +28,8 @@ import java.util.List; +import static java.util.Objects.requireNonNull; + /** Implementation of {@link org.apache.calcite.rel.core.Minus} in * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */ public class EnumerableMinus extends Minus implements EnumerableRel { @@ -69,7 +71,8 @@ public EnumerableMinus(RelOptCluster cluster, RelTraitSet traitSet, pref = pref.of(result.format); } - builder.add(minusExp); + builder.add( + requireNonNull(minusExp, () -> "minusExp is null, inputs=" + inputs + ", rel=" + this)); final PhysType physType = PhysTypeImpl.of( implementor.getTypeFactory(), diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelFactories.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelFactories.java index 927c6bced353..ad109c44d0b4 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelFactories.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelFactories.java @@ -95,7 +95,7 @@ private static class FilterFactoryImpl private static class SortFactoryImpl implements org.apache.calcite.rel.core.RelFactories.SortFactory { @Override public RelNode createSort(RelNode input, RelCollation collation, - RexNode offset, RexNode fetch) { + @Nullable RexNode offset, @Nullable RexNode fetch) { return EnumerableSort.create(input, collation, offset, fetch); } } diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java index 669a0c695a2a..5dda33f771e9 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRelImplementor.java @@ -70,6 +70,8 @@ import java.util.Map; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** * Subclass of {@link org.apache.calcite.plan.RelImplementor} for relational * operators of {@link EnumerableConvention} calling convention. @@ -121,7 +123,8 @@ public ClassDeclaration implementRoot(EnumerableRel rootRel, Expression e = null; for (Statement statement : result.block.statements) { if (statement instanceof GotoStatement) { - e = bb.append("v", ((GotoStatement) statement).expression); + e = bb.append("v", + requireNonNull(((GotoStatement) statement).expression, "expression")); } else { bb.add(statement); } diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortRule.java index a449c8bec7ad..14a9c8671a01 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortRule.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortRule.java @@ -21,6 +21,8 @@ import org.apache.calcite.rel.convert.ConverterRule; import org.apache.calcite.rel.core.Sort; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Rule to convert an {@link org.apache.calcite.rel.core.Sort} to an * {@link EnumerableSort}. @@ -39,7 +41,7 @@ protected EnumerableSortRule(Config config) { super(config); } - @Override public RelNode convert(RelNode rel) { + @Override public @Nullable RelNode convert(RelNode rel) { final Sort sort = (Sort) rel; if (sort.offset != null || sort.fetch != null) { return null; diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortedAggregate.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortedAggregate.java index 4d8ae6e4ad59..6b6562668ae3 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortedAggregate.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortedAggregate.java @@ -48,6 +48,8 @@ import java.util.ArrayList; import java.util.List; +import static java.util.Objects.requireNonNull; + /** Sort based physical implementation of {@link Aggregate} in * {@link EnumerableConvention enumerable calling convention}. */ public class EnumerableSortedAggregate extends EnumerableAggregateBase implements EnumerableRel { @@ -56,7 +58,7 @@ public EnumerableSortedAggregate( RelTraitSet traitSet, RelNode input, ImmutableBitSet groupSet, - List groupSets, + @Nullable List groupSets, List aggCalls) { super(cluster, traitSet, ImmutableList.of(), input, groupSet, groupSets, aggCalls); assert getConvention() instanceof EnumerableConvention; @@ -76,7 +78,8 @@ public EnumerableSortedAggregate( } RelTraitSet inputTraits = getInput().getTraitSet(); - RelCollation collation = required.getCollation(); + RelCollation collation = requireNonNull(required.getCollation(), + () -> "collation trait is null, required traits are " + required); ImmutableBitSet requiredKeys = ImmutableBitSet.of(RelCollations.ordinals(collation)); ImmutableBitSet groupKeys = ImmutableBitSet.range(groupSet.cardinality()); @@ -208,7 +211,9 @@ public EnumerableSortedAggregate( // Generate the appropriate key Comparator. In the case of NULL values // in group keys, the comparator must be able to support NULL values by giving a // consistent sort ordering. - final Expression comparator = keyPhysType.generateComparator(getTraitSet().getCollation()); + final Expression comparator = keyPhysType.generateComparator( + requireNonNull(getTraitSet().getCollation(), + () -> "getTraitSet().getCollation() is null, current traits are " + getTraitSet())); final Expression resultSelector_ = builder.append("resultSelector", diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortedAggregateRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortedAggregateRule.java index cfc3660af433..4808b500e0b6 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortedAggregateRule.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSortedAggregateRule.java @@ -25,6 +25,8 @@ import org.apache.calcite.rel.logical.LogicalAggregate; import org.apache.calcite.util.ImmutableIntList; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Rule to convert a {@link LogicalAggregate} @@ -44,7 +46,7 @@ protected EnumerableSortedAggregateRule(Config config) { super(config); } - @Override public RelNode convert(RelNode rel) { + @Override public @Nullable RelNode convert(RelNode rel) { final LogicalAggregate agg = (LogicalAggregate) rel; if (!Aggregate.isSimple(agg)) { return null; 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 dac38b5e6fbc..84e817859382 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 @@ -110,10 +110,10 @@ private Result defaultTableFunctionImplement( final JavaRowFormat format; if (getElementType() == null) { format = JavaRowFormat.ARRAY; - } else if (rowType.getFieldCount() == 1 && isQueryable()) { + } else if (getRowType().getFieldCount() == 1 && isQueryable()) { format = JavaRowFormat.SCALAR; } else if (getElementType() instanceof Class - && Object[].class.isAssignableFrom((Class) getElementType())) { + && Object[].class.isAssignableFrom((Class) getElementType())) { format = JavaRowFormat.ARRAY; } else { format = JavaRowFormat.CUSTOM; diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableModify.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableModify.java index b40c809f6799..d0084fc74725 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableModify.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableModify.java @@ -32,6 +32,8 @@ import org.apache.calcite.schema.ModifiableTable; import org.apache.calcite.util.BuiltInMethod; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -44,8 +46,8 @@ public class EnumerableTableModify extends TableModify implements EnumerableRel { public EnumerableTableModify(RelOptCluster cluster, RelTraitSet traits, RelOptTable table, Prepare.CatalogReader catalogReader, RelNode child, - Operation operation, List updateColumnList, - List sourceExpressionList, boolean flattened) { + Operation operation, @Nullable List updateColumnList, + @Nullable List sourceExpressionList, boolean flattened) { super(cluster, traits, table, catalogReader, child, operation, updateColumnList, sourceExpressionList, flattened); assert child.getConvention() instanceof EnumerableConvention; diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java index 626b33fd51c7..a2c60a4cb07b 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScan.java @@ -57,6 +57,10 @@ import java.util.ArrayList; import java.util.List; +import static org.apache.calcite.linq4j.tree.Types.toClass; + +import static java.util.Objects.requireNonNull; + /** Implementation of {@link org.apache.calcite.rel.core.TableScan} in * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */ public class EnumerableTableScan @@ -100,7 +104,7 @@ assert canHandle(table) /** Creates an EnumerableTableScan. */ public static EnumerableTableScan create(RelOptCluster cluster, RelOptTable relOptTable) { - final Table table = relOptTable.unwrap(Table.class); + final Table table = relOptTable.unwrapOrThrow(Table.class); Class elementType = EnumerableTableScan.deduceElementType(table); final RelTraitSet traitSet = cluster.traitSetOf(EnumerableConvention.INSTANCE) @@ -187,7 +191,7 @@ public static Class deduceElementType(Table table) { } public static JavaRowFormat deduceFormat(RelOptTable table) { - final Class elementType = deduceElementType(table.unwrap(Table.class)); + final Class elementType = deduceElementType(table.unwrapOrThrow(Table.class)); return elementType == Object[].class ? JavaRowFormat.ARRAY : JavaRowFormat.CUSTOM; @@ -208,7 +212,7 @@ private Expression getExpression(PhysType physType) { private Expression toEnumerable(Expression expression) { final Type type = expression.getType(); if (Types.isArray(type)) { - if (Types.toClass(type).getComponentType().isPrimitive()) { + if (requireNonNull(toClass(type).getComponentType()).isPrimitive()) { expression = Expressions.call(BuiltInMethod.AS_LIST.method, expression); } @@ -237,7 +241,7 @@ && getRowType().getFieldCount() == 1 return Expressions.call(BuiltInMethod.SLICE0.method, expression); } JavaRowFormat oldFormat = format(); - if (physType.getFormat() == oldFormat && !hasCollectionField(rowType)) { + if (physType.getFormat() == oldFormat && !hasCollectionField(getRowType())) { return expression; } final ParameterExpression row_ = @@ -262,7 +266,8 @@ private Expression fieldExpression(ParameterExpression row_, int i, switch (relFieldType.getSqlTypeName()) { case ARRAY: case MULTISET: - final RelDataType fieldType = relFieldType.getComponentType(); + final RelDataType fieldType = requireNonNull(relFieldType.getComponentType(), + () -> "relFieldType.getComponentType() for " + relFieldType); if (fieldType.isStruct()) { // We can't represent a multiset or array as a List, because // the consumer does not know the element type. diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScanRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScanRule.java index 1ecb22604272..9a4b3d8838fb 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScanRule.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScanRule.java @@ -24,6 +24,8 @@ import org.apache.calcite.schema.QueryableTable; import org.apache.calcite.schema.Table; +import org.checkerframework.checker.nullness.qual.Nullable; + /** Planner rule that converts a * {@link org.apache.calcite.rel.logical.LogicalTableScan} to * {@link EnumerableConvention enumerable calling convention}. @@ -43,7 +45,7 @@ protected EnumerableTableScanRule(Config config) { super(config); } - @Override public RelNode convert(RelNode rel) { + @Override public @Nullable RelNode convert(RelNode rel) { LogicalTableScan scan = (LogicalTableScan) rel; final RelOptTable relOptTable = scan.getTable(); final Table table = relOptTable.unwrap(Table.class); diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTraitsUtils.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTraitsUtils.java index 16dc2aa85575..3fddfbd2fd65 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTraitsUtils.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTraitsUtils.java @@ -39,6 +39,7 @@ import com.google.common.collect.ImmutableList; import org.apiguardian.api.API; +import org.checkerframework.checker.nullness.qual.Nullable; import java.util.ArrayList; import java.util.List; @@ -82,7 +83,7 @@ private static boolean isCollationOnTrivialExpr( return true; } - static Pair> passThroughTraitsForProject( + static @Nullable Pair> passThroughTraitsForProject( RelTraitSet required, List exps, RelDataType inputRowType, @@ -108,7 +109,7 @@ static Pair> passThroughTraitsForProject( ImmutableList.of(currentTraits.replace(newCollation))); } - static Pair> deriveTraitsForProject( + static @Nullable Pair> deriveTraitsForProject( RelTraitSet childTraits, int childId, List exps, RelDataType inputRowType, RelDataTypeFactory typeFactory, RelTraitSet currentTraits) { final RelCollation collation = childTraits.getCollation(); @@ -159,7 +160,7 @@ static Pair> deriveTraitsForProject( * @param leftInputFieldCount number of field count of left join input * @param joinTraitSet trait set of the join */ - static Pair> passThroughTraitsForJoin( + static @Nullable Pair> passThroughTraitsForJoin( RelTraitSet required, JoinRelType joinType, int leftInputFieldCount, RelTraitSet joinTraitSet) { RelCollation collation = required.getCollation(); @@ -194,7 +195,7 @@ static Pair> passThroughTraitsForJoin( * @param joinTraitSet trait set of the join * @param rightTraitSet trait set of the right join input */ - static Pair> deriveTraitsForJoin( + static @Nullable Pair> deriveTraitsForJoin( RelTraitSet childTraits, int childId, JoinRelType joinType, RelTraitSet joinTraitSet, RelTraitSet rightTraitSet) { // should only derive traits (limited to collation for now) from left join input. diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableUnion.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableUnion.java index 701cbd2a051d..5e53fc2c163f 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableUnion.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableUnion.java @@ -28,6 +28,8 @@ import java.util.List; +import static java.util.Objects.requireNonNull; + /** Implementation of {@link org.apache.calcite.rel.core.Union} in * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */ public class EnumerableUnion extends Union implements EnumerableRel { @@ -64,7 +66,7 @@ public EnumerableUnion(RelOptCluster cluster, RelTraitSet traitSet, } } - builder.add(unionExp); + builder.add(requireNonNull(unionExp, "unionExp")); final PhysType physType = PhysTypeImpl.of( implementor.getTypeFactory(), diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java index 611823ebd0f8..c732d14319dd 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java @@ -48,6 +48,8 @@ import java.util.ArrayList; import java.util.List; +import static java.util.Objects.requireNonNull; + /** Implementation of {@link org.apache.calcite.rel.core.Values} in * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */ public class EnumerableValues extends Values implements EnumerableRel { @@ -73,7 +75,7 @@ public static EnumerableValues create(RelOptCluster cluster, @Override public RelNode copy(RelTraitSet traitSet, List inputs) { assert inputs.isEmpty(); - return new EnumerableValues(getCluster(), rowType, tuples, traitSet); + return new EnumerableValues(getCluster(), getRowType(), tuples, traitSet); } @Override public @Nullable RelNode passThrough(final RelTraitSet required) { @@ -95,7 +97,7 @@ public static EnumerableValues create(RelOptCluster cluster, } } // Check whether the tuples are sorted by required collations. - if (!ordering.isOrdered(tuples)) { + if (!requireNonNull(ordering, "ordering").isOrdered(tuples)) { return null; } } @@ -128,7 +130,7 @@ public static EnumerableValues create(RelOptCluster cluster, final Type rowClass = physType.getJavaRowType(); final List expressions = new ArrayList<>(); - final List fields = rowType.getFieldList(); + final List fields = getRowType().getFieldList(); for (List tuple : tuples) { final List literals = new ArrayList<>(); for (Pair pair diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java index 6b99eab5a8ce..b7d2c231d072 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableWindow.java @@ -64,8 +64,13 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.function.Function; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + +import static java.util.Objects.requireNonNull; + /** Implementation of {@link org.apache.calcite.rel.core.Window} in * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}. */ public class EnumerableWindow extends Window implements EnumerableRel { @@ -104,7 +109,7 @@ private WindowRelInputGetter(Expression row, this.constants = constants; } - @Override public Expression field(BlockBuilder list, int index, Type storageType) { + @Override public Expression field(BlockBuilder list, int index, @Nullable Type storageType) { if (index < actualInputFieldCount) { Expression current = list.append("current", row); return rowPhysType.fieldReference(current, index, storageType); @@ -223,7 +228,10 @@ private void sampleOfTheGeneratedWindowedAggregate() { final RelDataTypeFactory.Builder typeBuilder = typeFactory.builder(); typeBuilder.addAll(inputPhysType.getRowType().getFieldList()); for (AggImpState agg : aggs) { - typeBuilder.add(agg.call.name, agg.call.type); + // CALCITE-4326 + String name = requireNonNull(agg.call.name, + () -> "agg.call.name for " + agg.call); + typeBuilder.add(name, agg.call.type); } RelDataType outputRowType = typeBuilder.build(); final PhysType outputPhysType = @@ -239,7 +247,7 @@ private void sampleOfTheGeneratedWindowedAggregate() { collectionExpr, BuiltInMethod.COLLECTION_SIZE.method)), false); - Pair collationKey = + Pair<@Nullable Expression, @Nullable Expression> collationKey = getRowCollationKey(builder, inputPhysType, group, windowIdx); Expression keySelector = collationKey.left; Expression keyComparator = collationKey.right; @@ -385,8 +393,9 @@ private void sampleOfTheGeneratedWindowedAggregate() { Expressions.statement(Expressions.assign(actualStart, startX))); for (final AggImpState agg : aggs) { - agg.implementor.implementReset(agg.context, - new WinAggResetContextImpl(builder6, agg.state, i_, startX, endX, + List aggState = requireNonNull(agg.state, "agg.state"); + agg.implementor.implementReset(requireNonNull(agg.context, "agg.context"), + new WinAggResetContextImpl(builder6, aggState, i_, startX, endX, hasRows, frameRowCount, partitionRowCount)); } @@ -832,15 +841,17 @@ private void declareAndResetState(final JavaTypeFactory typeFactory, builder.add( Expressions.declare(0, aggRes, - Expressions.constant(Primitive.is(aggRes.getType()) - ? Primitive.of(aggRes.getType()).defaultValue - : null, + Expressions.constant( + Optional.ofNullable(Primitive.of(aggRes.getType())) + .map(x -> x.defaultValue) + .orElse(null), aggRes.getType()))); agg.result = aggRes; outputRow.add(aggRes); agg.implementor.implementReset(agg.context, new WinAggResetContextImpl(builder, agg.state, - null, null, null, null, null, null)); + castNonNull(null), castNonNull(null), castNonNull(null), castNonNull(null), + castNonNull(null), castNonNull(null))); } } @@ -851,7 +862,7 @@ private void implementAdd(List aggs, final DeclarationStatement jDecl) { for (final AggImpState agg : aggs) { final WinAggAddContext addContext = - new WinAggAddContextImpl(builder7, agg.state, frame) { + new WinAggAddContextImpl(builder7, requireNonNull(agg.state, "agg.state"), frame) { @Override public Expression currentPosition() { return jDecl.parameter; } @@ -864,7 +875,7 @@ private void implementAdd(List aggs, return null; // REVIEW } }; - agg.implementor.implementAdd(agg.context, addContext); + agg.implementor.implementAdd(requireNonNull(agg.context, "agg.context"), addContext); } } @@ -886,17 +897,19 @@ private boolean implementResult(List aggs, continue; } nonEmpty = true; - Expression res = agg.implementor.implementResult(agg.context, - new WinAggResultContextImpl(builder, agg.state, frame) { + Expression res = agg.implementor.implementResult(requireNonNull(agg.context, "agg.context"), + new WinAggResultContextImpl(builder, requireNonNull(agg.state, "agg.state"), frame) { @Override public List rexArguments() { return rexArguments.apply(agg); } }); // Several count(a) and count(b) might share the result + Expression result = requireNonNull(agg.result, + () -> "agg.result for " + agg.call); Expression aggRes = builder.append("a" + agg.aggIdx + "res", - EnumUtils.convert(res, agg.result.getType())); + EnumUtils.convert(res, result.getType())); builder.add( - Expressions.statement(Expressions.assign(agg.result, aggRes))); + Expressions.statement(Expressions.assign(result, aggRes))); } return nonEmpty; } diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysType.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysType.java index 460ad8874eee..4f4eeaf649c8 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysType.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysType.java @@ -23,6 +23,8 @@ import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.util.Pair; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.reflect.Type; import java.util.List; @@ -92,7 +94,7 @@ public interface PhysType { * @return Expression to access the field of the expression */ Expression fieldReference(Expression expression, int field, - Type storageType); + @Nullable Type storageType); /** Generates an accessor function for a given list of fields. The resulting * object is a {@link List} (implementing {@link Object#hashCode()} and @@ -177,7 +179,7 @@ Expression generateComparator( /** Returns a expression that yields a comparer, or null if this type * is comparable. */ - Expression comparer(); + @Nullable Expression comparer(); /** Generates an expression that creates a record for a row, initializing * its fields with the given expressions. There must be one expression per diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java index b96ebf6d75e8..ad57cf3dc710 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/PhysTypeImpl.java @@ -40,6 +40,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.AbstractList; @@ -50,6 +52,8 @@ import static org.apache.calcite.adapter.enumerable.EnumUtils.generateCollatorExpression; import static org.apache.calcite.adapter.enumerable.EnumUtils.overridingMethodDecl; +import static java.util.Objects.requireNonNull; + /** Implementation of {@link PhysType}. */ public class PhysTypeImpl implements PhysType { private final JavaTypeFactory typeFactory; @@ -518,8 +522,10 @@ static PhysType of( @Override public PhysType component(int fieldOrdinal) { final RelDataTypeField field = rowType.getFieldList().get(fieldOrdinal); + RelDataType componentType = requireNonNull(field.getType().getComponentType(), + () -> "field.getType().getComponentType() for " + field); return PhysTypeImpl.of(typeFactory, - toStruct(field.getType().getComponentType()), format, false); + toStruct(componentType), format, false); } @Override public PhysType field(int ordinal) { @@ -537,7 +543,7 @@ private RelDataType toStruct(RelDataType type) { .build(); } - @Override public Expression comparer() { + @Override public @Nullable Expression comparer() { return format.comparer(); } @@ -669,7 +675,7 @@ private List fieldReferences( } @Override public Expression fieldReference( - Expression expression, int field, Type storageType) { + Expression expression, int field, @Nullable Type storageType) { Type fieldType; if (storageType == null) { storageType = fieldClass(field); diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java index 793785f26a4c..5a866cef62b4 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java @@ -302,6 +302,8 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.UPPER; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.USER; +import static java.util.Objects.requireNonNull; + /** * Contains implementations of Rex operators as Java code. */ @@ -714,7 +716,7 @@ private void defineMethod(SqlOperator operator, Method method, } private void defineUnary(SqlOperator operator, ExpressionType expressionType, - NullPolicy nullPolicy, String backupMethodName) { + NullPolicy nullPolicy, @Nullable String backupMethodName) { map.put(operator, new UnaryImplementor(expressionType, nullPolicy, backupMethodName)); } @@ -944,8 +946,8 @@ public Expression handle(Expression x) { } static Expression getDefaultValue(Type type) { - if (Primitive.is(type)) { - Primitive p = Primitive.of(type); + Primitive p = Primitive.of(type); + if (p != null) { return Expressions.constant(p.defaultValue, type); } return Expressions.constant(null, type); @@ -1379,7 +1381,10 @@ public UserDefinedAggReflectiveImplementor(AggregateFunctionImpl afi) { AggResultContext result) { List acc = result.accumulator(); return Expressions.call( - afi.isStatic ? null : acc.get(1), afi.resultMethod, acc.get(0)); + afi.isStatic ? null : acc.get(1), + requireNonNull(afi.resultMethod, + () -> "resultMethod is null. Does " + afi.declaringClass + " declare result method?"), + acc.get(0)); } } @@ -1393,8 +1398,9 @@ static class RankImplementor extends StrictWinAggImplementor { new Object() { int curentPosition; // position in for-win-agg-loop int startIndex; // index of start of window - Comparable[] rows; // accessed via WinAggAddContext.compareRows - { + Comparable @Nullable [] rows; // accessed via WinAggAddContext.compareRows + @SuppressWarnings("nullness") + void sample() { if (curentPosition > startIndex) { if (rows[curentPosition - 1].compareTo(rows[curentPosition]) > 0) { @@ -1914,7 +1920,8 @@ private static class FloorImplementor extends MethodNameImplementor { preFloor = false; } final TimeUnitRange timeUnitRange = - (TimeUnitRange) translator.getLiteralValue(argValueList.get(1)); + (TimeUnitRange) requireNonNull(translator.getLiteralValue(argValueList.get(1)), + "timeUnitRange"); switch (timeUnitRange) { case YEAR: case QUARTER: @@ -1948,7 +1955,7 @@ private Expression call(Expression operand, Type type, private static class MethodImplementor extends AbstractRexCallImplementor { protected final Method method; - MethodImplementor(Method method, NullPolicy nullPolicy, boolean harmonize) { + MethodImplementor(Method method, @Nullable NullPolicy nullPolicy, boolean harmonize) { super(nullPolicy, harmonize); this.method = method; } @@ -2193,10 +2200,10 @@ private Expression maybeBox(Expression expression) { /** Implementor for unary operators. */ private static class UnaryImplementor extends AbstractRexCallImplementor { private final ExpressionType expressionType; - private final String backupMethodName; + private final @Nullable String backupMethodName; UnaryImplementor(ExpressionType expressionType, NullPolicy nullPolicy, - String backupMethodName) { + @Nullable String backupMethodName) { super(nullPolicy, false); this.expressionType = expressionType; this.backupMethodName = backupMethodName; @@ -2244,7 +2251,7 @@ private static class ExtractImplementor extends AbstractRexCallImplementor { final RexCall call, final List argValueList) { final TimeUnitRange timeUnitRange = (TimeUnitRange) translator.getLiteralValue(argValueList.get(0)); - final TimeUnit unit = timeUnitRange.startUnit; + final TimeUnit unit = requireNonNull(timeUnitRange, "timeUnitRange").startUnit; Expression operand = argValueList.get(1); final SqlTypeName sqlTypeName = call.operands.get(1).getType().getSqlTypeName(); @@ -2464,10 +2471,10 @@ private static class CastImplementor extends AbstractRexCallImplementor { private RelDataType nullifyType(JavaTypeFactory typeFactory, final RelDataType type, final boolean nullable) { if (type instanceof RelDataTypeFactoryImpl.JavaType) { - final Primitive primitive = Primitive.ofBox( - ((RelDataTypeFactoryImpl.JavaType) type).getJavaClass()); - if (primitive != null) { - return typeFactory.createJavaType(primitive.primitiveClass); + Class javaClass = ((RelDataTypeFactoryImpl.JavaType) type).getJavaClass(); + final Class primitive = Primitive.unbox(javaClass); + if (primitive != javaClass) { + return typeFactory.createJavaType(primitive); } } return typeFactory.createTypeWithNullability(type, nullable); @@ -2801,7 +2808,7 @@ private static class LastImplementor implements MatchImplementor { // Just take the last one, if exists if ("*".equals(alpha)) { - ((EnumerableMatch.PassedRowsInputGetter) translator.inputGetter).setIndex(i); + setInputGetterIndex(translator, i); // Important, unbox the node / expression to avoid NullAs.NOT_POSSIBLE final RexPatternFieldRef ref = (RexPatternFieldRef) node; final RexPatternFieldRef newRef = @@ -2810,11 +2817,11 @@ private static class LastImplementor implements MatchImplementor { translator.typeFactory.createTypeWithNullability(ref.getType(), true)); final Expression expression = translator.translate(newRef, NullAs.NULL); - ((EnumerableMatch.PassedRowsInputGetter) translator.inputGetter).setIndex(null); + setInputGetterIndex(translator, null); return expression; } else { // Alpha != "*" so we have to search for a specific one to find and use that, if found - ((EnumerableMatch.PassedRowsInputGetter) translator.inputGetter).setIndex( + setInputGetterIndex(translator, Expressions.call(BuiltInMethod.MATCH_UTILS_LAST_WITH_SYMBOL.method, Expressions.constant(alpha), rows, symbols, i)); @@ -2826,10 +2833,15 @@ private static class LastImplementor implements MatchImplementor { translator.typeFactory.createTypeWithNullability(ref.getType(), true)); final Expression expression = translator.translate(newRef, NullAs.NULL); - ((EnumerableMatch.PassedRowsInputGetter) translator.inputGetter).setIndex(null); + setInputGetterIndex(translator, null); return expression; } } + + private void setInputGetterIndex(RexToLixTranslator translator, @Nullable Expression o) { + requireNonNull((EnumerableMatch.PassedRowsInputGetter) translator.inputGetter, + "inputGetter").setIndex(o); + } } /** Null-safe implementor of {@code RexCall}s. */ @@ -2858,10 +2870,10 @@ RexToLixTranslator.Result implement( */ private abstract static class AbstractRexCallImplementor implements RexCallImplementor { - final NullPolicy nullPolicy; + final @Nullable NullPolicy nullPolicy; private final boolean harmonize; - AbstractRexCallImplementor(NullPolicy nullPolicy, boolean harmonize) { + AbstractRexCallImplementor(@Nullable NullPolicy nullPolicy, boolean harmonize) { this.nullPolicy = nullPolicy; this.harmonize = harmonize; } @@ -3091,7 +3103,8 @@ private static class LogicalAndImplementor extends AbstractRexCallImplementor { @Override Expression implementSafe(final RexToLixTranslator translator, final RexCall call, final List argValueList) { - return null; + throw new IllegalStateException("This implementSafe should not be called," + + " please call implement(...)"); } } @@ -3147,7 +3160,8 @@ private static class LogicalOrImplementor extends AbstractRexCallImplementor { @Override Expression implementSafe(final RexToLixTranslator translator, final RexCall call, final List argValueList) { - return null; + throw new IllegalStateException("This implementSafe should not be called," + + " please call implement(...)"); } } @@ -3182,7 +3196,7 @@ private static class LogicalNotImplementor extends AbstractRexCallImplementor { private static class ReflectiveImplementor extends AbstractRexCallImplementor { protected final Method method; - ReflectiveImplementor(Method method, NullPolicy nullPolicy) { + ReflectiveImplementor(Method method, @Nullable NullPolicy nullPolicy) { super(nullPolicy, false); this.method = method; } @@ -3231,7 +3245,6 @@ private static class RandImplementor extends AbstractRexCallImplementor { /** Implementor for the {@code RAND_INTEGER} function. */ private static class RandIntegerImplementor extends AbstractRexCallImplementor { private final AbstractRexCallImplementor[] implementors = { - null, new ReflectiveImplementor(BuiltInMethod.RAND_INTEGER.method, nullPolicy), new ReflectiveImplementor(BuiltInMethod.RAND_INTEGER_SEED.method, nullPolicy) }; @@ -3246,7 +3259,7 @@ private static class RandIntegerImplementor extends AbstractRexCallImplementor { @Override Expression implementSafe(final RexToLixTranslator translator, final RexCall call, final List argValueList) { - return implementors[call.getOperands().size()] + return implementors[call.getOperands().size() - 1] .implementSafe(translator, call, argValueList); } } diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java index 610929a33fef..ee78362efd58 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java @@ -74,7 +74,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import static org.apache.calcite.sql.fun.SqlLibraryOperators.TRANSLATE3; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.CASE; @@ -85,6 +84,8 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.SUBSTRING; import static org.apache.calcite.sql.fun.SqlStdOperatorTable.UPPER; +import static java.util.Objects.requireNonNull; + /** * Translates {@link org.apache.calcite.rex.RexNode REX expressions} to * {@link Expression linq4j expressions}. @@ -131,7 +132,7 @@ public class RexToLixTranslator implements RexVisitor /** Map from RexNode under specific storage type to its Result, to avoid * generating duplicate code. For {@code RexInputRef}, {@code RexDynamicParam} * and {@code RexFieldAccess}. */ - private final Map, Result> rexWithStorageTypeResultMap = + private final Map, Result> rexWithStorageTypeResultMap = new HashMap<>(); /** Map from RexNode to its Result, to avoid generating duplicate code. @@ -158,12 +159,12 @@ private RexToLixTranslator(@Nullable RexProgram program, SqlConformance conformance, @Nullable Function1 correlates) { this.program = program; // may be null - this.typeFactory = Objects.requireNonNull(typeFactory); - this.conformance = Objects.requireNonNull(conformance); - this.root = Objects.requireNonNull(root); + this.typeFactory = requireNonNull(typeFactory); + this.conformance = requireNonNull(conformance); + this.root = requireNonNull(root); this.inputGetter = inputGetter; - this.list = Objects.requireNonNull(list); - this.builder = Objects.requireNonNull(builder); + this.list = requireNonNull(list); + this.builder = requireNonNull(builder); this.correlates = correlates; // may be null } @@ -469,7 +470,7 @@ Expression translateCast( Expressions.call( BuiltInMethod.INTERVAL_YEAR_MONTH_TO_STRING.method, operand, - Expressions.constant(interval.timeUnitRange))); + Expressions.constant(requireNonNull(interval, "interval").timeUnitRange))); break; case INTERVAL_DAY: case INTERVAL_DAY_HOUR: @@ -486,7 +487,7 @@ Expression translateCast( Expressions.call( BuiltInMethod.INTERVAL_DAY_TIME_TO_STRING.method, operand, - Expressions.constant(interval.timeUnitRange), + Expressions.constant(requireNonNull(interval, "interval").timeUnitRange), Expressions.constant( interval.getFractionalSecondPrecision( typeFactory.getTypeSystem())))); @@ -578,7 +579,9 @@ Expression translateCast( case INTERVAL_MINUTE: case INTERVAL_MINUTE_SECOND: case INTERVAL_SECOND: - switch (sourceType.getSqlTypeName().getFamily()) { + switch (requireNonNull(sourceType.getSqlTypeName().getFamily(), + () -> "null SqlTypeFamily for " + sourceType + ", SqlTypeName " + + sourceType.getSqlTypeName())) { case NUMERIC: final BigDecimal multiplier = targetType.getSqlTypeName().getEndUnit().multiplier; final BigDecimal divider = BigDecimal.ONE; @@ -594,7 +597,7 @@ Expression translateCast( return scaleIntervalToNumber(sourceType, targetType, convert); } - private Expression translateCastToTime(RelDataType sourceType, Expression operand) { + private @Nullable Expression translateCastToTime(RelDataType sourceType, Expression operand) { Expression convert = null; switch (sourceType.getSqlTypeName()) { case CHAR: @@ -632,7 +635,7 @@ private Expression translateCastToTime(RelDataType sourceType, Expression operan return convert; } - private Expression translateCastToDate(RelDataType sourceType, Expression operand) { + private @Nullable Expression translateCastToDate(RelDataType sourceType, Expression operand) { Expression convert = null; switch (sourceType.getSqlTypeName()) { case CHAR: @@ -691,7 +694,8 @@ Expression handleMethodCheckedExceptions(Expression callExpr) { public RexNode deref(RexNode expr) { if (expr instanceof RexLocalRef) { RexLocalRef ref = (RexLocalRef) expr; - final RexNode e2 = program.getExprList().get(ref.getIndex()); + final RexNode e2 = requireNonNull(program, "program") + .getExprList().get(ref.getIndex()); assert ref.getType().equals(e2.getType()); return e2; } else { @@ -745,7 +749,9 @@ public static Expression translateLiteral( } assert javaClass == BigDecimal.class; return Expressions.new_(BigDecimal.class, - Expressions.constant(bd.toString())); + Expressions.constant( + requireNonNull(bd, + () -> "value for " + literal).toString())); case DATE: case TIME: case TIME_WITH_LOCAL_TIME_ZONE: @@ -782,12 +788,14 @@ public static Expression translateLiteral( literal.getValueAs(byte[].class), byte[].class)); case GEOMETRY: - final Geometries.Geom geom = literal.getValueAs(Geometries.Geom.class); + final Geometries.Geom geom = requireNonNull(literal.getValueAs(Geometries.Geom.class), + () -> "getValueAs(Geometries.Geom) for " + literal); final String wkt = GeoFunctions.ST_AsWKT(geom); return Expressions.call(null, BuiltInMethod.ST_GEOM_FROM_TEXT.method, Expressions.constant(wkt)); case SYMBOL: - value2 = literal.getValueAs(Enum.class); + value2 = requireNonNull(literal.getValueAs(Enum.class), + () -> "getValueAs(Enum.class) for " + literal); javaClass = value2.getClass(); break; default: @@ -812,9 +820,9 @@ public List translateList( public List translateList( List operandList, RexImpTable.NullAs nullAs, - List storageTypes) { + List storageTypes) { final List list = new ArrayList<>(); - for (Pair e : Pair.zip(operandList, storageTypes)) { + for (Pair e : Pair.zip(operandList, storageTypes)) { list.add(translate(e.left, nullAs, e.right)); } return list; @@ -851,7 +859,7 @@ public List translateList(List operandList) { * @return translated expressions */ public List translateList(List operandList, - @Nullable List storageTypes) { + @Nullable List storageTypes) { final List list = new ArrayList<>(operandList.size()); for (int i = 0; i < operandList.size(); i++) { @@ -889,7 +897,8 @@ private Expression translateTableFunction(RexCall rexCall, Expression inputEnume public static Expression translateCondition(RexProgram program, JavaTypeFactory typeFactory, BlockBuilder list, InputGetter inputGetter, Function1 correlates, SqlConformance conformance) { - if (program.getCondition() == null) { + RexLocalRef condition = program.getCondition(); + if (condition == null) { return RexImpTable.TRUE_EXPR; } final ParameterExpression root = DataContext.ROOT; @@ -898,7 +907,7 @@ public static Expression translateCondition(RexProgram program, new RexBuilder(typeFactory), conformance, null); translator = translator.setCorrelates(correlates); return translator.translate( - program.getCondition(), + condition, RexImpTable.NullAs.FALSE); } @@ -935,7 +944,8 @@ private static Expression scaleIntervalToNumber( RelDataType sourceType, RelDataType targetType, Expression operand) { - switch (targetType.getSqlTypeName().getFamily()) { + switch (requireNonNull(targetType.getSqlTypeName().getFamily(), + () -> "SqlTypeFamily for " + targetType)) { case NUMERIC: switch (sourceType.getSqlTypeName()) { case INTERVAL_YEAR: @@ -979,7 +989,7 @@ private static Expression scaleIntervalToNumber( * } */ @Override public Result visitInputRef(RexInputRef inputRef) { - final Pair key = Pair.of(inputRef, currentStorageType); + final Pair key = Pair.of(inputRef, currentStorageType); // If the RexInputRef has been visited under current storage type already, // it is not necessary to visit it again, just return the result. if (rexWithStorageTypeResultMap.containsKey(key)) { @@ -987,7 +997,7 @@ private static Expression scaleIntervalToNumber( } // Generate one line of code to get the input, e.g., // "final Employee current =(Employee) inputEnumerator.current();" - final Expression valueExpression = inputGetter.field( + final Expression valueExpression = requireNonNull(inputGetter, "inputGetter").field( list, inputRef.getIndex(), currentStorageType); // Generate one line of code for the value of RexInputRef, e.g., @@ -1125,7 +1135,7 @@ private ConstantExpression getTypedNullLiteral(RexLiteral literal) { throw new RuntimeException("cannot translate call " + call); } final List operandList = call.getOperands(); - final List storageTypes = EnumUtils.internalTypes(operandList); + final List<@Nullable Type> storageTypes = EnumUtils.internalTypes(operandList); final List operandResults = new ArrayList<>(); for (int i = 0; i < operandList.size(); i++) { final Result operandResult = @@ -1139,7 +1149,7 @@ private ConstantExpression getTypedNullLiteral(RexLiteral literal) { } private static Result implementCallOperand(final RexNode operand, - final Type storageType, final RexToLixTranslator translator) { + final @Nullable Type storageType, final RexToLixTranslator translator) { final Type originalStorageType = translator.currentStorageType; translator.currentStorageType = storageType; Result operandResult = operand.accept(translator); @@ -1151,7 +1161,7 @@ private static Result implementCallOperand(final RexNode operand, } private static Expression implementCallOperand2(final RexNode operand, - final Type storageType, final RexToLixTranslator translator) { + final @Nullable Type storageType, final RexToLixTranslator translator) { final Type originalStorageType = translator.currentStorageType; translator.currentStorageType = storageType; final Expression result = translator.translate(operand); @@ -1168,7 +1178,8 @@ private Result implementPrev(RexCall call) { final RexNode offset = call.getOperands().get(1); final Expression offs = Expressions.multiply(translate(offset), Expressions.constant(-1)); - ((EnumerableMatch.PrevInputGetter) inputGetter).setOffset(offs); + requireNonNull((EnumerableMatch.PrevInputGetter) inputGetter, "inputGetter") + .setOffset(offs); return node.accept(this); } @@ -1230,7 +1241,7 @@ private Result implementCaseWhen(RexCall call) { private void implementRecursively(final RexToLixTranslator currentTranslator, final List operandList, final ParameterExpression valueVariable, int pos) { final BlockBuilder currentBlockBuilder = currentTranslator.getBlockBuilder(); - final List storageTypes = EnumUtils.internalTypes(operandList); + final List<@Nullable Type> storageTypes = EnumUtils.internalTypes(operandList); // [ELSE] clause if (pos == operandList.size() - 1) { Expression res = implementCallOperand2(operandList.get(pos), @@ -1295,7 +1306,7 @@ private Result toInnerStorageType(final Result result, final Type storageType) { } @Override public Result visitDynamicParam(RexDynamicParam dynamicParam) { - final Pair key = Pair.of(dynamicParam, currentStorageType); + final Pair key = Pair.of(dynamicParam, currentStorageType); if (rexWithStorageTypeResultMap.containsKey(key)) { return rexWithStorageTypeResultMap.get(key); } @@ -1317,7 +1328,7 @@ private Result toInnerStorageType(final Result result, final Type storageType) { } @Override public Result visitFieldAccess(RexFieldAccess fieldAccess) { - final Pair key = Pair.of(fieldAccess, currentStorageType); + final Pair key = Pair.of(fieldAccess, currentStorageType); if (rexWithStorageTypeResultMap.containsKey(key)) { return rexWithStorageTypeResultMap.get(key); } @@ -1408,11 +1419,12 @@ BlockBuilder getBlockBuilder() { } Expression getLiteral(Expression literalVariable) { - return literalMap.get(literalVariable); + return requireNonNull(literalMap.get(literalVariable), + () -> "literalMap.get(literalVariable) for " + literalVariable); } /** Returns the value of a literal. */ - @Nullable Object getLiteralValue(Expression expr) { + @Nullable Object getLiteralValue(@Nullable Expression expr) { if (expr instanceof ParameterExpression) { final Expression constantExpr = literalMap.get(expr); return getLiteralValue(constantExpr); @@ -1424,12 +1436,13 @@ Expression getLiteral(Expression literalVariable) { } List getCallOperandResult(RexCall call) { - return callOperandResultMap.get(call); + return requireNonNull(callOperandResultMap.get(call), + () -> "callOperandResultMap.get(call) for " + call); } /** Translates a field of an input to an expression. */ public interface InputGetter { - Expression field(BlockBuilder list, int index, Type storageType); + Expression field(BlockBuilder list, int index, @Nullable Type storageType); } /** Implementation of {@link InputGetter} that calls @@ -1441,7 +1454,7 @@ public InputGetterImpl(List> inputs) { this.inputs = inputs; } - @Override public Expression field(BlockBuilder list, int index, Type storageType) { + @Override public Expression field(BlockBuilder list, int index, @Nullable Type storageType) { int offset = 0; for (Pair input : inputs) { final PhysType physType = input.right; diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/StrictAggImplementor.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/StrictAggImplementor.java index 3b77c3c50f87..4531b607d33c 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/StrictAggImplementor.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/StrictAggImplementor.java @@ -119,9 +119,10 @@ protected void implementNotNullReset(AggContext info, final List conditions = new ArrayList<>(); conditions.addAll( translator.translateList(args, RexImpTable.NullAs.IS_NOT_NULL)); - if (add.rexFilterArgument() != null) { + RexNode filterArgument = add.rexFilterArgument(); + if (filterArgument != null) { conditions.add( - translator.translate(add.rexFilterArgument(), + translator.translate(filterArgument, RexImpTable.NullAs.FALSE)); } Expression condition = Expressions.foldAnd(conditions); diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResultContextImpl.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResultContextImpl.java index c146706f6fa7..b36d670f1365 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResultContextImpl.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/impl/AggResultContextImpl.java @@ -23,17 +23,21 @@ import org.apache.calcite.linq4j.tree.ParameterExpression; import org.apache.calcite.rel.core.AggregateCall; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Implementation of * {@link org.apache.calcite.adapter.enumerable.AggResultContext}. */ public class AggResultContextImpl extends AggResetContextImpl implements AggResultContext { - private final AggregateCall call; - private final ParameterExpression key; - private final PhysType keyPhysType; + private final @Nullable AggregateCall call; + private final @Nullable ParameterExpression key; + private final @Nullable PhysType keyPhysType; /** * Creates aggregate result context. @@ -44,24 +48,25 @@ public class AggResultContextImpl extends AggResetContextImpl * aggregate state * @param key Key */ - public AggResultContextImpl(BlockBuilder block, AggregateCall call, - List accumulator, ParameterExpression key, - PhysType keyPhysType) { + public AggResultContextImpl(BlockBuilder block, @Nullable AggregateCall call, + List accumulator, @Nullable ParameterExpression key, + @Nullable PhysType keyPhysType) { super(block, accumulator); - this.call = call; + this.call = call; // null for AggAddContextImpl this.key = key; - this.keyPhysType = keyPhysType; + this.keyPhysType = keyPhysType; // null for AggAddContextImpl } - @Override public Expression key() { + @Override public @Nullable Expression key() { return key; } @Override public Expression keyField(int i) { - return keyPhysType.fieldReference(key, i); + return requireNonNull(keyPhysType, "keyPhysType") + .fieldReference(requireNonNull(key, "key"), i); } @Override public AggregateCall call() { - return call; + return requireNonNull(call, "call"); } } diff --git a/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java b/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java index a3392fa147b8..e9c5ce5c5943 100644 --- a/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java +++ b/core/src/main/java/org/apache/calcite/adapter/java/ReflectiveSchema.java @@ -64,7 +64,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; + +import static java.util.Objects.requireNonNull; /** * Implementation of {@link org.apache.calcite.schema.Schema} that exposes the @@ -130,7 +131,7 @@ private Map createTableMap() { throw new RuntimeException( "Error while accessing field " + field, e); } - Objects.requireNonNull(rc, () -> "field must not be null: " + field); + requireNonNull(rc, () -> "field must not be null: " + field); FieldTable table = (FieldTable) tableMap.get(Util.last(rc.getSourceQualifiedName())); assert table != null; @@ -177,7 +178,7 @@ private Multimap createFunctionMap() { /** Returns an expression for the object wrapped by this schema (not the * schema itself). */ - Expression getTargetExpression(SchemaPlus parentSchema, String name) { + Expression getTargetExpression(@Nullable SchemaPlus parentSchema, String name) { return EnumUtils.convert( Expressions.call( Schemas.unwrap( @@ -201,6 +202,7 @@ Expression getTargetExpression(SchemaPlus parentSchema, String name) { throw new RuntimeException( "Error while accessing field " + field, e); } + requireNonNull(o, () -> "field " + field + " is null for " + target); @SuppressWarnings("unchecked") final Enumerable enumerable = toEnumerable(o); return new FieldTable<>(field, elementType, enumerable); @@ -252,7 +254,7 @@ private static class ReflectiveTable return Statistics.UNKNOWN; } - @Override public Enumerable scan(DataContext root) { + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { if (elementType == Object[].class) { //noinspection unchecked return enumerable; @@ -324,6 +326,7 @@ public static class Factory implements SchemaFactory { //noinspection unchecked Method method = clazz.getMethod((String) methodName); target = method.invoke(null); + requireNonNull(target, () -> "method " + method + " returns null"); } catch (Exception e) { throw new RuntimeException("Error invoking method " + methodName, e); } @@ -359,7 +362,9 @@ private static class MethodTableMacro extends ReflectiveFunctionBase @Override public TranslatableTable apply(final List arguments) { try { - final Object o = method.invoke(schema.getTarget(), arguments.toArray()); + final Object o = requireNonNull( + method.invoke(schema.getTarget(), arguments.toArray()), + () -> "method " + method + " returned null for arguments " + arguments); return (TranslatableTable) o; } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); @@ -395,23 +400,26 @@ private static class FieldTable extends ReflectiveTable { @Override public Expression getExpression(SchemaPlus schema, String tableName, Class clazz) { + ReflectiveSchema reflectiveSchema = requireNonNull( + schema.unwrap(ReflectiveSchema.class), + () -> "schema.unwrap(ReflectiveSchema.class) for " + schema); return Expressions.field( - schema.unwrap(ReflectiveSchema.class).getTargetExpression( + reflectiveSchema.getTargetExpression( schema.getParentSchema(), schema.getName()), field); } } /** Function that returns an array of a given object's field values. */ - private static class FieldSelector implements Function1 { + private static class FieldSelector implements Function1 { private final Field[] fields; FieldSelector(Class elementType) { this.fields = elementType.getFields(); } - @Override public Object[] apply(Object o) { + @Override public @Nullable Object[] apply(Object o) { try { - final Object[] objects = new Object[fields.length]; + final @Nullable Object[] objects = new Object[fields.length]; for (int i = 0; i < fields.length; i++) { objects[i] = fields[i].get(o); } diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcCatalogSchema.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcCatalogSchema.java index feecda495d6b..95a4f61edbf2 100644 --- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcCatalogSchema.java +++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcCatalogSchema.java @@ -32,13 +32,16 @@ import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMap; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Map; -import java.util.Objects; import javax.sql.DataSource; +import static java.util.Objects.requireNonNull; + /** * Schema based upon a JDBC catalog (database). * @@ -58,20 +61,21 @@ public class JdbcCatalogSchema extends AbstractSchema { final String catalog; /** Sub-schemas by name, lazily initialized. */ + @SuppressWarnings("method.invocation.invalid") final Supplier subSchemaMapSupplier = Suppliers.memoize(() -> computeSubSchemaMap()); /** Creates a JdbcCatalogSchema. */ public JdbcCatalogSchema(DataSource dataSource, SqlDialect dialect, JdbcConvention convention, String catalog) { - this.dataSource = Objects.requireNonNull(dataSource); - this.dialect = Objects.requireNonNull(dialect); - this.convention = Objects.requireNonNull(convention); + this.dataSource = requireNonNull(dataSource); + this.dialect = requireNonNull(dialect); + this.convention = requireNonNull(convention); this.catalog = catalog; } public static JdbcCatalogSchema create( - SchemaPlus parentSchema, + @Nullable SchemaPlus parentSchema, String name, DataSource dataSource, String catalog) { @@ -80,7 +84,7 @@ public static JdbcCatalogSchema create( } public static JdbcCatalogSchema create( - SchemaPlus parentSchema, + @Nullable SchemaPlus parentSchema, String name, DataSource dataSource, SqlDialectFactory dialectFactory, @@ -107,7 +111,9 @@ private SubSchemaMap computeSubSchemaMap() { connection.getMetaData().getSchemas(catalog, null)) { defaultSchemaName = connection.getSchema(); while (resultSet.next()) { - final String schemaName = resultSet.getString(1); + final String schemaName = requireNonNull( + resultSet.getString(1), + () -> "got null schemaName from the database"); builder.put(schemaName, new JdbcSchema(dataSource, dialect, convention, catalog, schemaName)); } diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcQueryProvider.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcQueryProvider.java index f58e25015e3a..c816f7d4573f 100644 --- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcQueryProvider.java +++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcQueryProvider.java @@ -21,6 +21,8 @@ import org.apache.calcite.linq4j.QueryProviderImpl; import org.apache.calcite.linq4j.Queryable; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Implementation of {@link QueryProvider} that talks to JDBC databases. */ @@ -31,6 +33,6 @@ private JdbcQueryProvider() { } @Override public Enumerator executeQuery(Queryable queryable) { - return null; + return castNonNull(null); } } diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java index c12344a07dd9..54f66d0815df 100644 --- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java +++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java @@ -84,6 +84,8 @@ import java.util.Set; import java.util.function.Consumer; +import static java.util.Objects.requireNonNull; + /** * Rules and relational operators for * {@link JdbcConvention} @@ -116,7 +118,8 @@ private JdbcRules() { static final RelFactories.JoinFactory JOIN_FACTORY = (left, right, hints, condition, variablesSet, joinType, semiJoinDone) -> { final RelOptCluster cluster = left.getCluster(); - final RelTraitSet traitSet = cluster.traitSetOf(left.getConvention()); + final RelTraitSet traitSet = cluster.traitSetOf( + requireNonNull(left.getConvention(), "left.getConvention()")); try { return new JdbcJoin(cluster, traitSet, left, right, condition, variablesSet, joinType); @@ -148,7 +151,8 @@ private JdbcRules() { public static final RelFactories.AggregateFactory AGGREGATE_FACTORY = (input, hints, groupSet, groupSets, aggCalls) -> { final RelOptCluster cluster = input.getCluster(); - final RelTraitSet traitSet = cluster.traitSetOf(input.getConvention()); + final RelTraitSet traitSet = cluster.traitSetOf( + requireNonNull(input.getConvention(), "input.getConvention()")); try { return new JdbcAggregate(cluster, traitSet, input, groupSet, groupSets, aggCalls); @@ -168,7 +172,8 @@ private JdbcRules() { (kind, inputs, all) -> { RelNode input = inputs.get(0); RelOptCluster cluster = input.getCluster(); - final RelTraitSet traitSet = cluster.traitSetOf(input.getConvention()); + final RelTraitSet traitSet = cluster.traitSetOf( + requireNonNull(input.getConvention(), "input.getConvention()")); switch (kind) { case UNION: return new JdbcUnion(cluster, traitSet, inputs, all); @@ -693,7 +698,7 @@ public JdbcAggregate( RelTraitSet traitSet, RelNode input, ImmutableBitSet groupSet, - List groupSets, + @Nullable List groupSets, List aggCalls) throws InvalidRelException { super(cluster, traitSet, ImmutableList.of(), input, groupSet, groupSets, aggCalls); @@ -1013,8 +1018,8 @@ public JdbcTableModify(RelOptCluster cluster, Prepare.CatalogReader catalogReader, RelNode input, Operation operation, - List updateColumnList, - List sourceExpressionList, + @Nullable List updateColumnList, + @Nullable List sourceExpressionList, boolean flattened) { super(cluster, traitSet, table, catalogReader, input, operation, updateColumnList, sourceExpressionList, flattened); 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 ce63e5bfe95a..fe4565d3907b 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 @@ -201,8 +201,8 @@ public static SqlDialect createDialect(SqlDialectFactory dialectFactory, } /** Creates a JDBC data source with the given specification. */ - public static DataSource dataSource(String url, String driverClassName, - String username, String password) { + public static DataSource dataSource(String url, @Nullable String driverClassName, + @Nullable String username, @Nullable String password) { if (url.startsWith("jdbc:hsqldb:")) { // Prevent hsqldb from screwing up java.util.logging. System.setProperty("hsqldb.reconfig_logging", "false"); @@ -225,7 +225,7 @@ public DataSource getDataSource() { return dataSource; } - @Override public Expression getExpression(SchemaPlus parentSchema, String name) { + @Override public Expression getExpression(@Nullable SchemaPlus parentSchema, String name) { return Schemas.subSchemaExpression(parentSchema, name, JdbcSchema.class); } @@ -251,8 +251,9 @@ private ImmutableMap computeTables() { final String catalog = catalogSchema.left; final String schema = catalogSchema.right; final Iterable tableDefs; - if (THREAD_METADATA.get() != null) { - tableDefs = THREAD_METADATA.get().apply(catalog, schema); + Foo threadMetadata = THREAD_METADATA.get(); + if (threadMetadata != null) { + tableDefs = threadMetadata.apply(catalog, schema); } else { final List tableDefList = new ArrayList<>(); final DatabaseMetaData metaData = connection.getMetaData(); @@ -491,7 +492,8 @@ protected Map getTypes() { } @Override public Set getTypeNames() { - return getTypes().keySet(); + //noinspection RedundantCast + return (Set) getTypes().keySet(); } @Override public @Nullable Schema getSubSchema(String name) { diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java index 809f887a1943..6b2ab112be4d 100644 --- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java +++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTable.java @@ -60,7 +60,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Objects; + +import static java.util.Objects.requireNonNull; /** * Queryable that gets its data from a table within a JDBC connection. @@ -74,7 +75,7 @@ */ public class JdbcTable extends AbstractQueryableTable implements TranslatableTable, ScannableTable, ModifiableTable { - private RelProtoDataType protoRowType; + private @Nullable RelProtoDataType protoRowType; public final JdbcSchema jdbcSchema; public final String jdbcCatalogName; public final String jdbcSchemaName; @@ -85,11 +86,11 @@ public class JdbcTable extends AbstractQueryableTable String jdbcSchemaName, String jdbcTableName, Schema.TableType jdbcTableType) { super(Object[].class); - this.jdbcSchema = Objects.requireNonNull(jdbcSchema); + this.jdbcSchema = requireNonNull(jdbcSchema); this.jdbcCatalogName = jdbcCatalogName; this.jdbcSchemaName = jdbcSchemaName; - this.jdbcTableName = Objects.requireNonNull(jdbcTableName); - this.jdbcTableType = Objects.requireNonNull(jdbcTableType); + this.jdbcTableName = requireNonNull(jdbcTableName); + this.jdbcTableType = requireNonNull(jdbcTableType); } @Override public String toString() { @@ -100,7 +101,7 @@ public class JdbcTable extends AbstractQueryableTable return jdbcTableType; } - @Override public @Nullable C unwrap(Class aClass) { + @Override public @Nullable C unwrap(Class aClass) { if (aClass.isInstance(jdbcSchema.getDataSource())) { return aClass.cast(jdbcSchema.getDataSource()); } else if (aClass.isInstance(jdbcSchema.dialect)) { @@ -129,7 +130,7 @@ public class JdbcTable extends AbstractQueryableTable private List> fieldClasses( final JavaTypeFactory typeFactory) { - final RelDataType rowType = protoRowType.apply(typeFactory); + final RelDataType rowType = requireNonNull(protoRowType, "protoRowType").apply(typeFactory); return Util.transform(rowType.getFieldList(), f -> { final RelDataType type = f.getType(); final Class clazz = (Class) typeFactory.getJavaClass(type); @@ -178,21 +179,21 @@ public SqlIdentifier tableName() { return new JdbcTableQueryable<>(queryProvider, schema, tableName); } - @Override public Enumerable scan(DataContext root) { - final JavaTypeFactory typeFactory = root.getTypeFactory(); + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { + JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory"); final SqlString sql = generateSql(); return ResultSetEnumerable.of(jdbcSchema.getDataSource(), sql.getSql(), JdbcUtils.ObjectArrayRowBuilder.factory(fieldClasses(typeFactory))); } - @Override public Collection getModifiableCollection() { + @Override public @Nullable Collection getModifiableCollection() { return null; } @Override public TableModify toModificationRel(RelOptCluster cluster, RelOptTable table, CatalogReader catalogReader, RelNode input, - Operation operation, List updateColumnList, - List sourceExpressionList, boolean flattened) { + Operation operation, @Nullable List updateColumnList, + @Nullable List sourceExpressionList, boolean flattened) { jdbcSchema.convention.register(cluster.getPlanner()); return new LogicalTableModify(cluster, cluster.traitSetOf(Convention.NONE), diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java index 25d8a145bca1..ee201f32de48 100644 --- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java +++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcTableScan.java @@ -27,6 +27,8 @@ import java.util.List; import java.util.Objects; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Relational expression representing a scan of a table in a JDBC data source. */ @@ -45,7 +47,7 @@ protected JdbcTableScan( @Override public RelNode copy(RelTraitSet traitSet, List inputs) { assert inputs.isEmpty(); return new JdbcTableScan( - getCluster(), table, jdbcTable, (JdbcConvention) getConvention()); + getCluster(), table, jdbcTable, (JdbcConvention) castNonNull(getConvention())); } @Override public JdbcImplementor.Result implement(JdbcImplementor implementor) { diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcUtils.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcUtils.java index 7639d0c6b6a4..70609737e067 100644 --- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcUtils.java +++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcUtils.java @@ -32,6 +32,9 @@ import com.google.common.cache.LoadingCache; import com.google.common.primitives.Ints; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.PolyNull; + import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.Date; @@ -44,6 +47,7 @@ import java.util.TimeZone; import javax.sql.DataSource; + /** * Utilities for the JDBC provider. */ @@ -95,7 +99,7 @@ public SqlDialect get(SqlDialectFactory dialectFactory, DataSource dataSource) { /** Builder that calls {@link ResultSet#getObject(int)} for every column, * or {@code getXxx} if the result type is a primitive {@code xxx}, * and returns an array of objects for each row. */ - static class ObjectArrayRowBuilder implements Function0 { + static class ObjectArrayRowBuilder implements Function0<@Nullable Object[]> { private final ResultSet resultSet; private final int columnCount; private final ColumnMetaData.Rep[] reps; @@ -110,7 +114,7 @@ static class ObjectArrayRowBuilder implements Function0 { this.columnCount = resultSet.getMetaData().getColumnCount(); } - public static Function1> factory( + public static Function1> factory( final List> list) { return resultSet -> { try { @@ -124,9 +128,9 @@ public static Function1> factory( }; } - @Override public Object[] apply() { + @Override public @Nullable Object[] apply() { try { - final Object[] values = new Object[columnCount]; + final @Nullable Object[] values = new Object[columnCount]; for (int i = 0; i < columnCount; i++) { values[i] = value(i); } @@ -141,7 +145,7 @@ public static Function1> factory( * * @param i Ordinal of column (1-based, per JDBC) */ - private Object value(int i) throws SQLException { + private @Nullable Object value(int i) throws SQLException { // MySQL returns timestamps shifted into local time. Using // getTimestamp(int, Calendar) with a UTC calendar should prevent this, // but does not. So we shift explicitly. @@ -158,7 +162,7 @@ private Object value(int i) throws SQLException { return reps[i].jdbcGet(resultSet, i + 1); } - private static Timestamp shift(Timestamp v) { + private static @PolyNull Timestamp shift(@PolyNull Timestamp v) { if (v == null) { return null; } @@ -167,7 +171,7 @@ private static Timestamp shift(Timestamp v) { return new Timestamp(time + offset); } - private static Time shift(Time v) { + private static @PolyNull Time shift(@PolyNull Time v) { if (v == null) { return null; } @@ -176,7 +180,7 @@ private static Time shift(Time v) { return new Time((time + offset) % DateTimeUtils.MILLIS_PER_DAY); } - private static Date shift(Date v) { + private static @PolyNull Date shift(@PolyNull Date v) { if (v == null) { return null; } @@ -196,12 +200,12 @@ private static Date shift(Date v) { static class DataSourcePool { public static final DataSourcePool INSTANCE = new DataSourcePool(); - private final LoadingCache, BasicDataSource> cache = + private final LoadingCache, BasicDataSource> cache = CacheBuilder.newBuilder().softValues() .build(CacheLoader.from(DataSourcePool::dataSource)); private static BasicDataSource dataSource( - List key) { + List key) { BasicDataSource dataSource = new BasicDataSource(); dataSource.setUrl(key.get(0)); dataSource.setUsername(key.get(1)); @@ -210,11 +214,11 @@ private static BasicDataSource dataSource( return dataSource; } - public DataSource get(String url, String driverClassName, - String username, String password) { + public DataSource get(String url, @Nullable String driverClassName, + @Nullable String username, @Nullable String password) { // Get data source objects from a cache, so that we don't have to sniff // out what kind of database they are quite as often. - final List key = + final List<@Nullable String> key = ImmutableNullableList.of(url, username, password, driverClassName); return cache.getUnchecked(key); } diff --git a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java index 8474cf0afce2..cea5c6a17eb1 100644 --- a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java +++ b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfig.java @@ -22,6 +22,7 @@ import org.apache.calcite.model.JsonSchema; import org.apache.calcite.sql.validate.SqlConformance; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; import java.util.Properties; @@ -60,7 +61,7 @@ public interface CalciteConnectionConfig extends ConnectionConfig { /** Returns the value of {@link CalciteConnectionProperty#FUN}. */ @PolyNull T fun(Class operatorTableClass, @PolyNull T defaultOperatorTable); /** Returns the value of {@link CalciteConnectionProperty#MODEL}. */ - String model(); + @Nullable String model(); /** Returns the value of {@link CalciteConnectionProperty#LEX}. */ Lex lex(); /** Returns the value of {@link CalciteConnectionProperty#QUOTING}. */ diff --git a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java index 699ec091e385..204568b9ca30 100644 --- a/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java +++ b/core/src/main/java/org/apache/calcite/config/CalciteConnectionConfigImpl.java @@ -27,6 +27,7 @@ import org.apache.calcite.sql.validate.SqlConformance; import org.apache.calcite.sql.validate.SqlConformanceEnum; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; import java.util.List; @@ -119,7 +120,7 @@ public boolean isSet(CalciteConnectionProperty property) { return operatorTableClass.cast(operatorTable); } - @Override public String model() { + @Override public @Nullable String model() { return CalciteConnectionProperty.MODEL.wrap(properties).getString(); } diff --git a/core/src/main/java/org/apache/calcite/config/CalciteSystemProperty.java b/core/src/main/java/org/apache/calcite/config/CalciteSystemProperty.java index ac27b01c2fd6..4fd3a75645ee 100644 --- a/core/src/main/java/org/apache/calcite/config/CalciteSystemProperty.java +++ b/core/src/main/java/org/apache/calcite/config/CalciteSystemProperty.java @@ -19,6 +19,8 @@ import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableSet; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -248,7 +250,7 @@ public final class CalciteSystemProperty { // The name of the property is not appropriate. A better alternative would be // calcite.test.foodmart.queries.ids. Moreover, I am not in favor of using system properties for // parameterized tests. - public static final CalciteSystemProperty TEST_FOODMART_QUERY_IDS = + public static final CalciteSystemProperty<@Nullable String> TEST_FOODMART_QUERY_IDS = new CalciteSystemProperty<>("calcite.ids", Function.identity()); /** @@ -441,7 +443,8 @@ private static Properties loadProperties() { private final T value; - private CalciteSystemProperty(String key, Function valueParser) { + private CalciteSystemProperty(String key, + Function valueParser) { this.value = valueParser.apply(PROPERTIES.getProperty(key)); } diff --git a/core/src/main/java/org/apache/calcite/interpreter/AggregateNode.java b/core/src/main/java/org/apache/calcite/interpreter/AggregateNode.java index 5bc65695c58f..9c2917b9b730 100644 --- a/core/src/main/java/org/apache/calcite/interpreter/AggregateNode.java +++ b/core/src/main/java/org/apache/calcite/interpreter/AggregateNode.java @@ -54,10 +54,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Supplier; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + +import static java.util.Objects.requireNonNull; + /** * Interpreter node that implements an * {@link org.apache.calcite.rel.core.Aggregate}. @@ -88,7 +91,9 @@ public AggregateNode(Compiler compiler, Aggregate rel) { ImmutableList.Builder builder = ImmutableList.builder(); for (AggregateCall aggregateCall : rel.getAggCallList()) { - builder.add(getAccumulator(aggregateCall, false)); + @SuppressWarnings("method.invocation.invalid") + AccumulatorFactory accumulator = getAccumulator(aggregateCall, false); + builder.add(accumulator); } accumulatorFactories = builder.build(); } @@ -196,7 +201,7 @@ private AccumulatorFactory getAccumulator(final AggregateCall call, (JavaTypeFactory) rel.getCluster().getTypeFactory(); int stateOffset = 0; final AggImpState agg = new AggImpState(0, call, false); - int stateSize = agg.state.size(); + int stateSize = requireNonNull(agg.state, "agg.state").size(); final BlockBuilder builder2 = new BlockBuilder(); final PhysType inputPhysType = @@ -249,7 +254,7 @@ private AccumulatorFactory getAccumulator(final AggregateCall call, } }; - agg.implementor.implementAdd(agg.context, addContext); + agg.implementor.implementAdd(requireNonNull(agg.context, "agg.context"), addContext); final ParameterExpression context_ = Expressions.parameter(Context.class, "context"); @@ -257,13 +262,13 @@ private AccumulatorFactory getAccumulator(final AggregateCall call, Expressions.parameter(Object[].class, "outputValues"); Scalar addScalar = JaninoRexCompiler.baz(context_, outputValues_, builder2.toBlock()); - return new ScalarAccumulatorDef(null, addScalar, null, + return new ScalarAccumulatorDef(castNonNull(null), addScalar, castNonNull(null), rel.getInput().getRowType().getFieldCount(), stateSize, dataContext); } } private AggregateFunctionImpl getAggFunction(Class clazz) { - return Objects.requireNonNull( + return requireNonNull( AggregateFunctionImpl.create(clazz), () -> "Unable to create AggregateFunctionImpl for " + clazz); } @@ -340,16 +345,20 @@ private ScalarAccumulator(ScalarAccumulatorDef def, Object[] values) { } @Override public void send(Row row) { - System.arraycopy(row.getValues(), 0, def.sendContext.values, 0, + @Nullable Object[] sendValues = requireNonNull(def.sendContext.values, + "def.sendContext.values"); + System.arraycopy(row.getValues(), 0, sendValues, 0, def.rowLength); - System.arraycopy(values, 0, def.sendContext.values, def.rowLength, - values.length); - def.addScalar.execute(def.sendContext, values); + System.arraycopy(this.values, 0, sendValues, def.rowLength, + this.values.length); + def.addScalar.execute(def.sendContext, this.values); } @Override public @Nullable Object end() { - System.arraycopy(values, 0, def.endContext.values, 0, values.length); - return def.endScalar.execute(def.endContext); + Context endContext = requireNonNull(def.endContext, "def.endContext"); + @Nullable Object[] values = requireNonNull(endContext.values, "endContext.values"); + System.arraycopy(this.values, 0, values, 0, this.values.length); + return def.endScalar.execute(endContext); } } @@ -737,7 +746,10 @@ private static class UdaAccumulator implements Accumulator { } final @Nullable Object[] args = {value}; try { - return factory.aggFunction.resultMethod.invoke(factory.instance, args); + AggregateFunctionImpl aggFunction = requireNonNull(factory.aggFunction, + "factory.aggFunction"); + return requireNonNull(aggFunction.resultMethod, "aggFunction.resultMethod") + .invoke(factory.instance, args); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } diff --git a/core/src/main/java/org/apache/calcite/interpreter/Bindables.java b/core/src/main/java/org/apache/calcite/interpreter/Bindables.java index e6feef7b7475..8c02dfa64735 100644 --- a/core/src/main/java/org/apache/calcite/interpreter/Bindables.java +++ b/core/src/main/java/org/apache/calcite/interpreter/Bindables.java @@ -156,7 +156,7 @@ private Bindables() {} *

Any bindable can be compiled; if its input is also bindable, it becomes * part of the same compilation unit. */ - private static Enumerable help(DataContext dataContext, + private static Enumerable<@Nullable Object[]> help(DataContext dataContext, BindableRel rel) { return new Interpreter(dataContext, rel); } @@ -291,7 +291,7 @@ public static boolean canHandle(RelOptTable table) { || table.unwrap(ProjectableFilterableTable.class) != null; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return help(dataContext, this); } @@ -356,7 +356,7 @@ public static BindableFilter create(final RelNode input, return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return help(dataContext, this); } @@ -415,7 +415,7 @@ public BindableProject(RelOptCluster cluster, RelTraitSet traitSet, return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return help(dataContext, this); } @@ -473,7 +473,7 @@ public BindableSort(RelOptCluster cluster, RelTraitSet traitSet, return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return help(dataContext, this); } @@ -545,7 +545,7 @@ protected BindableJoin(RelOptCluster cluster, RelTraitSet traitSet, return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return help(dataContext, this); } @@ -606,7 +606,7 @@ public BindableUnion(RelOptCluster cluster, RelTraitSet traitSet, return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return help(dataContext, this); } @@ -632,7 +632,7 @@ public BindableIntersect(RelOptCluster cluster, RelTraitSet traitSet, return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return help(dataContext, this); } @@ -657,7 +657,7 @@ public BindableMinus(RelOptCluster cluster, RelTraitSet traitSet, return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return help(dataContext, this); } @@ -683,7 +683,7 @@ public static class BindableValues extends Values implements BindableRel { return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return help(dataContext, this); } @@ -770,7 +770,7 @@ public BindableAggregate(RelOptCluster cluster, RelTraitSet traitSet, return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return help(dataContext, this); } @@ -833,7 +833,7 @@ public static class BindableWindow extends Window implements BindableRel { return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return help(dataContext, this); } @@ -897,7 +897,7 @@ public static class BindableMatch extends Match implements BindableRel { return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return help(dataContext, this); } diff --git a/core/src/main/java/org/apache/calcite/interpreter/InterpretableConverter.java b/core/src/main/java/org/apache/calcite/interpreter/InterpretableConverter.java index a7c84ba427e5..26e431828a3f 100644 --- a/core/src/main/java/org/apache/calcite/interpreter/InterpretableConverter.java +++ b/core/src/main/java/org/apache/calcite/interpreter/InterpretableConverter.java @@ -25,6 +25,8 @@ import org.apache.calcite.rel.convert.ConverterImpl; import org.apache.calcite.runtime.ArrayBindable; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -47,7 +49,7 @@ protected InterpretableConverter(RelOptCluster cluster, RelTraitSet traits, return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return new Interpreter(dataContext, getInput()); } } diff --git a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java index 49a52f298877..6658c89b43e5 100644 --- a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java +++ b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java @@ -17,6 +17,7 @@ package org.apache.calcite.interpreter; import org.apache.calcite.DataContext; +import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.config.CalciteSystemProperty; import org.apache.calcite.linq4j.AbstractEnumerable; import org.apache.calcite.linq4j.Enumerable; @@ -66,7 +67,10 @@ import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; -import java.util.Objects; + +import static org.apache.calcite.linq4j.Nullness.castNonNull; + +import static java.util.Objects.requireNonNull; /** * Interpreter. @@ -75,7 +79,7 @@ * particular it holds working state while the data flow graph is being * assembled. */ -public class Interpreter extends AbstractEnumerable +public class Interpreter extends AbstractEnumerable<@Nullable Object[]> implements AutoCloseable { private final Map nodes; private final DataContext dataContext; @@ -83,7 +87,7 @@ public class Interpreter extends AbstractEnumerable /** Creates an Interpreter. */ public Interpreter(DataContext dataContext, RelNode rootRel) { - this.dataContext = Objects.requireNonNull(dataContext); + this.dataContext = requireNonNull(dataContext); final RelNode rel = optimize(rootRel); final CompilerImpl compiler = new Nodes.CoreCompiler(this, rootRel.getCluster()); @@ -108,9 +112,10 @@ private static RelNode optimize(RelNode rootRel) { return rootRel; } - @Override public Enumerator enumerator() { + @Override public Enumerator<@Nullable Object[]> enumerator() { start(); - final NodeInfo nodeInfo = nodes.get(rootRel); + final NodeInfo nodeInfo = requireNonNull(nodes.get(rootRel), + () -> "nodeInfo for " + rootRel); final Enumerator rows; if (nodeInfo.rowEnumerable != null) { rows = nodeInfo.rowEnumerable.enumerator(); @@ -120,8 +125,8 @@ private static RelNode optimize(RelNode rootRel) { rows = Linq4j.iterableEnumerator(queue); } - return new TransformedEnumerator(rows) { - @Override protected Object[] transform(Row row) { + return new TransformedEnumerator(rows) { + @Override protected @Nullable Object[] transform(Row row) { return row.getValues(); } }; @@ -244,7 +249,8 @@ private class FooCompiler implements ScalarCompiler { case LITERAL: return ((RexLiteral) node).getValueAs(Comparable.class); case INPUT_REF: - return context.values[((RexInputRef) node).getIndex()]; + @Nullable Object[] values = requireNonNull(context.values, "context.values"); + return values[((RexInputRef) node).getIndex()]; default: throw new RuntimeException("unknown expression type " + node); } @@ -274,7 +280,7 @@ private static class EnumeratorSource implements Source { private final Enumerator enumerator; EnumeratorSource(final Enumerator enumerator) { - this.enumerator = Objects.requireNonNull(enumerator); + this.enumerator = requireNonNull(enumerator); } @Override public @Nullable Row receive() { @@ -412,7 +418,7 @@ static class CompilerImpl extends RelVisitor Pair> visitRoot(RelNode p) { rootRel = p; visit(p, 0, null); - return Pair.of(rootRel, nodes); + return Pair.of(requireNonNull(rootRel, "rootRel"), nodes); } @Override public void visit(RelNode p, int ordinal, @Nullable RelNode parent) { @@ -429,7 +435,7 @@ Pair> visitRoot(RelNode p) { if (CalciteSystemProperty.DEBUG.value()) { System.out.println("Interpreter: rewrite " + p + " to " + rel); } - p = rel; + p = requireNonNull(rel, "rel"); if (parent != null) { List inputs = relInputs.get(parent); if (inputs == null) { @@ -461,8 +467,10 @@ Pair> visitRoot(RelNode p) { if (!found) { if (p instanceof InterpretableRel) { InterpretableRel interpretableRel = (InterpretableRel) p; + // TODO: analyze if null is permissible argument for dataContext node = interpretableRel.implement( - new InterpretableRel.InterpreterImplementor(this, null, null)); + new InterpretableRel.InterpreterImplementor(this, null, + castNonNull(null))); } else { // Probably need to add a visit(XxxRel) method to CoreCompiler. throw new AssertionError("interpreter: no implementation for " @@ -490,15 +498,20 @@ public void rewrite(RelNode r) { @Override public Scalar compile(List nodes, @Nullable RelDataType inputRowType) { if (inputRowType == null) { - inputRowType = interpreter.dataContext.getTypeFactory().builder() + inputRowType = getTypeFactory().builder() .build(); } return scalarCompiler.compile(nodes, inputRowType); } + private JavaTypeFactory getTypeFactory() { + return requireNonNull(interpreter.dataContext.getTypeFactory(), + () -> "no typeFactory in dataContext"); + } + @Override public RelDataType combinedRowType(List inputs) { final RelDataTypeFactory.Builder builder = - interpreter.dataContext.getTypeFactory().builder(); + getTypeFactory().builder(); for (RelNode input : inputs) { builder.addAll(input.getRowType().getFieldList()); } diff --git a/core/src/main/java/org/apache/calcite/interpreter/Interpreters.java b/core/src/main/java/org/apache/calcite/interpreter/Interpreters.java index 2ae81a3ca665..9bb42719d8a7 100644 --- a/core/src/main/java/org/apache/calcite/interpreter/Interpreters.java +++ b/core/src/main/java/org/apache/calcite/interpreter/Interpreters.java @@ -21,6 +21,8 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.runtime.ArrayBindable; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Utilities relating to {@link org.apache.calcite.interpreter.Interpreter} * and {@link org.apache.calcite.interpreter.InterpretableConvention}. @@ -36,7 +38,7 @@ public static ArrayBindable bindable(final RelNode rel) { return (ArrayBindable) rel; } return new ArrayBindable() { - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return new Interpreter(dataContext, rel); } diff --git a/core/src/main/java/org/apache/calcite/interpreter/JoinNode.java b/core/src/main/java/org/apache/calcite/interpreter/JoinNode.java index 36a3aa4dda3e..6d88213f3b34 100644 --- a/core/src/main/java/org/apache/calcite/interpreter/JoinNode.java +++ b/core/src/main/java/org/apache/calcite/interpreter/JoinNode.java @@ -21,12 +21,15 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Objects; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** * Interpreter node that implements a * {@link org.apache.calcite.rel.core.Join}. @@ -83,7 +86,8 @@ public JoinNode(Compiler compiler, Join rel) { if (rel.getJoinType() == JoinRelType.FULL) { // send un-match rows for full join on right source List empty = new ArrayList<>(); - for (Row row: innerRows) { + // TODO: CALCITE-4308, JointNode in Interpreter might fail with NPE for FULL join + for (Row row: requireNonNull(innerRows, "innerRows")) { if (matchRowSet.contains(row)) { continue; } @@ -125,7 +129,7 @@ private void doSend(Row outerRow, List matchInnerRows, case FULL: boolean outerRowOnLeft = joinRelType != JoinRelType.RIGHT; copyToContext(outerRow, outerRowOnLeft); - Objects.requireNonNull(context.values, "context.values"); + requireNonNull(context.values, "context.values"); for (Row row: matchInnerRows) { copyToContext(row, !outerRowOnLeft); sink.send(Row.asCopy(context.values)); @@ -142,7 +146,7 @@ private void doSend(Row outerRow, List matchInnerRows, case LEFT: case RIGHT: case FULL: - Objects.requireNonNull(context.values, "context.values"); + requireNonNull(context.values, "context.values"); int nullColumnNum = context.values.length - outerRow.size(); // for full join, use left source as outer source, // and send un-match rows in left source fist, @@ -166,8 +170,8 @@ private void doSend(Row outerRow, List matchInnerRows, * Copies the value of row into context values. */ private void copyToContext(Row row, boolean toLeftSide) { - Object[] values = row.getValues(); - Objects.requireNonNull(context.values, "context.values"); + @Nullable Object[] values = row.getValues(); + requireNonNull(context.values, "context.values"); if (toLeftSide) { System.arraycopy(values, 0, context.values, 0, values.length); } else { diff --git a/core/src/main/java/org/apache/calcite/interpreter/SortNode.java b/core/src/main/java/org/apache/calcite/interpreter/SortNode.java index 9c4dc3e4f00a..b7a85a252d84 100644 --- a/core/src/main/java/org/apache/calcite/interpreter/SortNode.java +++ b/core/src/main/java/org/apache/calcite/interpreter/SortNode.java @@ -19,6 +19,7 @@ import org.apache.calcite.rel.RelFieldCollation; import org.apache.calcite.rel.core.Sort; import org.apache.calcite.rex.RexLiteral; +import org.apache.calcite.rex.RexNode; import org.apache.calcite.util.Util; import com.google.common.collect.Ordering; @@ -27,6 +28,8 @@ import java.util.Comparator; import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Interpreter node that implements a * {@link org.apache.calcite.rel.core.Sort}. @@ -36,15 +39,20 @@ public SortNode(Compiler compiler, Sort rel) { super(compiler, rel); } + private static int getValueAsInt(RexNode node) { + return requireNonNull(((RexLiteral) node).getValueAs(Integer.class), + () -> "getValueAs(Integer.class) for " + node); + } + @Override public void run() throws InterruptedException { final int offset = rel.offset == null ? 0 - : ((RexLiteral) rel.offset).getValueAs(Integer.class); + : getValueAsInt(rel.offset); final int fetch = rel.fetch == null ? -1 - : ((RexLiteral) rel.fetch).getValueAs(Integer.class); + : getValueAsInt(rel.fetch); // In pure limit mode. No sort required. Row row; loop: diff --git a/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java b/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java index 18819eaf656d..75a5a930d51a 100644 --- a/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java +++ b/core/src/main/java/org/apache/calcite/interpreter/TableScanNode.java @@ -51,10 +51,11 @@ import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.List; -import java.util.Objects; import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * Interpreter node that implements a * {@link org.apache.calcite.rel.core.TableScan}. @@ -128,6 +129,8 @@ private static TableScanNode createQueryable(Compiler compiler, final Type elementType = queryableTable.getElementType(); SchemaPlus schema = root.getRootSchema(); for (String name : Util.skipLast(relOptTable.getQualifiedName())) { + requireNonNull(schema, () -> "schema is null while resolving " + name + " for table" + + relOptTable.getQualifiedName()); schema = schema.getSubSchema(name); } final Enumerable rowEnumerable; @@ -170,7 +173,7 @@ private static TableScanNode createFilterable(Compiler compiler, FilterableTable filterableTable) { final DataContext root = compiler.getDataContext(); final List mutableFilters = Lists.newArrayList(filters); - final Enumerable enumerable = + final Enumerable<@Nullable Object[]> enumerable = filterableTable.scan(root, mutableFilters); for (RexNode filter : mutableFilters) { if (!filters.contains(filter)) { @@ -196,7 +199,7 @@ private static TableScanNode createProjectableFilterable(Compiler compiler, } else { projectInts = projects.toIntArray(); } - final Enumerable enumerable1 = + final Enumerable<@Nullable Object[]> enumerable1 = pfTable.scan(root, mutableFilters, projectInts); for (RexNode filter : mutableFilters) { if (!filters.contains(filter)) { @@ -225,7 +228,7 @@ private static TableScanNode createProjectableFilterable(Compiler compiler, } final Enumerable rowEnumerable = Enumerables.toRow(enumerable1); final ImmutableIntList rejectedProjects; - if (Objects.equals(projects, originalProjects)) { + if (originalProjects == null || originalProjects.equals(projects)) { rejectedProjects = null; } else { // We projected extra columns because they were needed in filters. Now diff --git a/core/src/main/java/org/apache/calcite/interpreter/ValuesNode.java b/core/src/main/java/org/apache/calcite/interpreter/ValuesNode.java index ac399a6dfde8..6800f949b6ec 100644 --- a/core/src/main/java/org/apache/calcite/interpreter/ValuesNode.java +++ b/core/src/main/java/org/apache/calcite/interpreter/ValuesNode.java @@ -37,10 +37,11 @@ public class ValuesNode implements Node { public ValuesNode(Compiler compiler, Values rel) { this.sink = compiler.sink(rel); this.fieldCount = rel.getRowType().getFieldCount(); - this.rows = createRows(compiler, rel.getTuples()); + this.rows = createRows(compiler, fieldCount, rel.getTuples()); } - private ImmutableList createRows(Compiler compiler, + private static ImmutableList createRows(Compiler compiler, + int fieldCount, ImmutableList> tuples) { final List nodes = new ArrayList<>(); for (ImmutableList tuple : tuples) { diff --git a/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java index f464e338a346..1c62d913ab73 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java @@ -39,6 +39,8 @@ import java.util.List; import java.util.Set; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Concrete implementation of {@link CalciteSchema} that caches tables, * functions and sub-schemas. @@ -56,6 +58,7 @@ class CachingCalciteSchema extends CalciteSchema { this(parent, schema, name, null, null, null, null, null, null, null, null); } + @SuppressWarnings({"argument.type.incompatible", "return.type.incompatible"}) private CachingCalciteSchema(@Nullable CalciteSchema parent, Schema schema, String name, @Nullable NameMap subSchemaMap, @@ -302,7 +305,7 @@ private interface Cached { * * @param element type */ private abstract class AbstractCached implements Cached { - T t; + @Nullable T t; boolean built = false; @Override public T get(long now) { @@ -313,7 +316,7 @@ private abstract class AbstractCached implements Cached { t = build(); } built = true; - return t; + return castNonNull(t); } @Override public void enable(long now, boolean enabled) { diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java index 2bda7138ac7d..a4d1dd275641 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteConnectionImpl.java @@ -86,6 +86,8 @@ import java.util.TimeZone; import java.util.concurrent.atomic.AtomicBoolean; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Implementation of JDBC connection * in the Calcite engine. @@ -269,11 +271,11 @@ CalcitePrepare.CalciteSignature parseQuery( } @Override public T execute(Expression expression, Type type) { - return null; // TODO: + return castNonNull(null); // TODO: } @Override public T execute(Expression expression, Class type) { - return null; // TODO: + return castNonNull(null); // TODO: } @Override public Enumerator executeQuery(Queryable queryable) { @@ -383,7 +385,7 @@ static class RootSchema extends AbstractSchema { super(); } - @Override public Expression getExpression(SchemaPlus parentSchema, + @Override public Expression getExpression(@Nullable SchemaPlus parentSchema, String name) { return Expressions.call( DataContext.ROOT, @@ -494,7 +496,7 @@ private SqlAdvisor getSqlAdvisor() { return typeFactory; } - @Override public @Nullable QueryProvider getQueryProvider() { + @Override public QueryProvider getQueryProvider() { return queryProvider; } } @@ -593,8 +595,8 @@ private static class SlimDataContext implements DataContext, Serializable { static class CalciteServerStatementImpl implements CalciteServerStatement { private final CalciteConnectionImpl connection; - private Iterator iterator; - private Meta.Signature signature; + private @Nullable Iterator iterator; + private Meta.@Nullable Signature signature; private final AtomicBoolean cancelFlag = new AtomicBoolean(); CalciteServerStatementImpl(CalciteConnectionImpl connection) { @@ -613,11 +615,11 @@ static class CalciteServerStatementImpl this.signature = signature; } - @Override public Meta.Signature getSignature() { + @Override public Meta.@Nullable Signature getSignature() { return signature; } - @Override public Iterator getResultSet() { + @Override public @Nullable Iterator getResultSet() { return iterator; } diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java index 7d04bef7d018..1707834f16d8 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteJdbc41Factory.java @@ -152,7 +152,7 @@ private static class CalciteJdbc41PreparedStatement @Override public void setNCharacterStream( int parameterIndex, - Reader value, + @Nullable Reader value, long length) throws SQLException { getSite(parameterIndex) .setNCharacterStream(value, length); @@ -160,13 +160,13 @@ private static class CalciteJdbc41PreparedStatement @Override public void setNClob( int parameterIndex, - NClob value) throws SQLException { + @Nullable NClob value) throws SQLException { getSite(parameterIndex).setNClob(value); } @Override public void setClob( int parameterIndex, - Reader reader, + @Nullable Reader reader, long length) throws SQLException { getSite(parameterIndex) .setClob(reader, length); @@ -174,7 +174,7 @@ private static class CalciteJdbc41PreparedStatement @Override public void setBlob( int parameterIndex, - InputStream inputStream, + @Nullable InputStream inputStream, long length) throws SQLException { getSite(parameterIndex) .setBlob(inputStream, length); @@ -182,7 +182,7 @@ private static class CalciteJdbc41PreparedStatement @Override public void setNClob( int parameterIndex, - Reader reader, + @Nullable Reader reader, long length) throws SQLException { getSite(parameterIndex).setNClob(reader, length); } @@ -194,7 +194,7 @@ private static class CalciteJdbc41PreparedStatement @Override public void setAsciiStream( int parameterIndex, - InputStream x, + @Nullable InputStream x, long length) throws SQLException { getSite(parameterIndex) .setAsciiStream(x, length); @@ -202,7 +202,7 @@ private static class CalciteJdbc41PreparedStatement @Override public void setBinaryStream( int parameterIndex, - InputStream x, + @Nullable InputStream x, long length) throws SQLException { getSite(parameterIndex) .setBinaryStream(x, length); @@ -210,48 +210,48 @@ private static class CalciteJdbc41PreparedStatement @Override public void setCharacterStream( int parameterIndex, - Reader reader, + @Nullable Reader reader, long length) throws SQLException { getSite(parameterIndex) .setCharacterStream(reader, length); } @Override public void setAsciiStream( - int parameterIndex, InputStream x) throws SQLException { + int parameterIndex, @Nullable InputStream x) throws SQLException { getSite(parameterIndex).setAsciiStream(x); } @Override public void setBinaryStream( - int parameterIndex, InputStream x) throws SQLException { + int parameterIndex, @Nullable InputStream x) throws SQLException { getSite(parameterIndex).setBinaryStream(x); } @Override public void setCharacterStream( - int parameterIndex, Reader reader) throws SQLException { + int parameterIndex, @Nullable Reader reader) throws SQLException { getSite(parameterIndex) .setCharacterStream(reader); } @Override public void setNCharacterStream( - int parameterIndex, Reader value) throws SQLException { + int parameterIndex, @Nullable Reader value) throws SQLException { getSite(parameterIndex) .setNCharacterStream(value); } @Override public void setClob( int parameterIndex, - Reader reader) throws SQLException { + @Nullable Reader reader) throws SQLException { getSite(parameterIndex).setClob(reader); } @Override public void setBlob( - int parameterIndex, InputStream inputStream) throws SQLException { + int parameterIndex, @Nullable InputStream inputStream) throws SQLException { getSite(parameterIndex) .setBlob(inputStream); } @Override public void setNClob( - int parameterIndex, Reader reader) throws SQLException { + int parameterIndex, @Nullable Reader reader) throws SQLException { getSite(parameterIndex) .setNClob(reader); } diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java index ad97e4eb0d54..80389879ea88 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteMetaImpl.java @@ -73,9 +73,10 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.regex.Pattern; +import static java.util.Objects.requireNonNull; + /** * Helper for implementing the {@code getXxx} methods such as * {@link org.apache.calcite.avatica.AvaticaDatabaseMetaData#getTables}. @@ -164,7 +165,7 @@ public static Pattern likeToRegex(Pat pattern) { private MetaResultSet createResultSet(Enumerable enumerable, Class clazz, String... names) { - Objects.requireNonNull(names); + requireNonNull(names); final List columns = new ArrayList<>(names.length); final List fields = new ArrayList<>(names.length); final List fieldNames = new ArrayList<>(names.length); @@ -383,8 +384,9 @@ Enumerable tables(final MetaSchema schema_) { final CalciteMetaSchema schema = (CalciteMetaSchema) schema_; return Linq4j.asEnumerable(schema.calciteSchema.getTableNames()) .select((Function1) name -> { - final Table table = - schema.calciteSchema.getTable(name, true).getTable(); + final Table table = requireNonNull( + schema.calciteSchema.getTable(name, true), + () -> "table " + name + " is not found (case sensitive)").getTable(); return new CalciteMetaTable(table, schema.tableCatalog, schema.tableSchem, @@ -678,7 +680,7 @@ private CalcitePrepare.Query toQuery( final Meta.PrepareCallback callback = new Meta.PrepareCallback() { long updateCount; - Signature signature; + @Nullable Signature signature; @Override public Object getMonitor() { return statement; @@ -693,6 +695,7 @@ private CalcitePrepare.Query toQuery( } @Override public void execute() throws SQLException { + Signature signature = requireNonNull(this.signature, "signature"); if (signature.statementType.canUpdate()) { final Iterable iterable = _createIterable(h, signature, ImmutableList.of(), @@ -746,7 +749,7 @@ private static class CalciteMetaTable extends MetaTable { String tableSchem, String tableName) { super(tableCat, tableSchem, tableName, calciteTable.getJdbcTableType().jdbcName); - this.calciteTable = Objects.requireNonNull(calciteTable); + this.calciteTable = requireNonNull(calciteTable); } } 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 8c1d83eec4ec..866cf4293086 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalcitePrepare.java @@ -339,7 +339,7 @@ public CalciteSignature(String sql, List parameterList, castNonNull(null)); } - public CalciteSignature(String sql, + public CalciteSignature(@Nullable String sql, List parameterList, Map internalParameters, @Nullable RelDataType 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 191b504ead5b..fd0f2b76dc1a 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java @@ -655,7 +655,7 @@ CalciteSchema calciteSchema() { throw new UnsupportedOperationException(); } - @Override public Expression getExpression(SchemaPlus parentSchema, String name) { + @Override public Expression getExpression(@Nullable SchemaPlus parentSchema, String name) { return schema.getExpression(parentSchema, name); } @@ -701,7 +701,7 @@ CalciteSchema calciteSchema() { return calciteSchema.plus(); } - @Override public T unwrap(Class clazz) { + @Override public T unwrap(Class clazz) { if (clazz.isInstance(this)) { return clazz.cast(this); } diff --git a/core/src/main/java/org/apache/calcite/jdbc/Driver.java b/core/src/main/java/org/apache/calcite/jdbc/Driver.java index 2f824d3a60cb..06aa637b68e1 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/Driver.java +++ b/core/src/main/java/org/apache/calcite/jdbc/Driver.java @@ -58,6 +58,7 @@ public class Driver extends UnregisteredDriver { new Driver().register(); } + @SuppressWarnings("method.invocation.invalid") public Driver() { super(); this.prepareFactory = createPrepareFactory(); @@ -105,7 +106,7 @@ protected Function0 createPrepareFactory() { connection.init(); } - String model(CalciteConnectionImpl connection) { + @Nullable String model(CalciteConnectionImpl connection) { String model = connection.config().model(); if (model != null) { return model; @@ -131,17 +132,17 @@ String model(CalciteConnectionImpl connection) { } if (schemaFactory != null) { final JsonBuilder json = new JsonBuilder(); - final Map root = json.map(); + final Map root = json.map(); root.put("version", "1.0"); root.put("defaultSchema", schemaName); - final List schemaList = json.list(); + final List<@Nullable Object> schemaList = json.list(); root.put("schemas", schemaList); - final Map schema = json.map(); + final Map schema = json.map(); schemaList.add(schema); schema.put("type", "custom"); schema.put("name", schemaName); schema.put("factory", schemaFactory.getClass().getName()); - final Map operandMap = json.map(); + final Map operandMap = json.map(); schema.put("operand", operandMap); for (Map.Entry entry : Util.toMap(info).entrySet()) { if (entry.getKey().startsWith("schema.")) { diff --git a/core/src/main/java/org/apache/calcite/jdbc/JavaCollation.java b/core/src/main/java/org/apache/calcite/jdbc/JavaCollation.java index 5d2ee5381ad6..421d6a840439 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/JavaCollation.java +++ b/core/src/main/java/org/apache/calcite/jdbc/JavaCollation.java @@ -59,7 +59,7 @@ private static String getStrengthString(int strengthValue) { } @Override protected String generateCollationName( - @UnderInitialization(SqlCollation.class) JavaCollation this, + @UnderInitialization JavaCollation this, Charset charset) { return super.generateCollationName(charset) + "$JAVA_COLLATOR"; } diff --git a/core/src/main/java/org/apache/calcite/jdbc/JavaRecordType.java b/core/src/main/java/org/apache/calcite/jdbc/JavaRecordType.java index 55680bffb967..43aaa1cade93 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/JavaRecordType.java +++ b/core/src/main/java/org/apache/calcite/jdbc/JavaRecordType.java @@ -42,7 +42,7 @@ public JavaRecordType(List fields, Class clazz) { @Override public boolean equals(@Nullable Object obj) { return this == obj || obj instanceof JavaRecordType - && fieldList.equals(((JavaRecordType) obj).fieldList) + && Objects.equals(fieldList, ((JavaRecordType) obj).fieldList) && clazz == ((JavaRecordType) obj).clazz; } diff --git a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java index b0430a3a0618..d0c9908d5639 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java +++ b/core/src/main/java/org/apache/calcite/jdbc/JavaTypeFactoryImpl.java @@ -243,7 +243,7 @@ private Type fieldType(Field field) { default: break; } - return null; + return Object.class; } @Override public RelDataType toSql(RelDataType type) { diff --git a/core/src/main/java/org/apache/calcite/materialize/MaterializationActor.java b/core/src/main/java/org/apache/calcite/materialize/MaterializationActor.java index 28d7daa82d04..839c576228ee 100644 --- a/core/src/main/java/org/apache/calcite/materialize/MaterializationActor.java +++ b/core/src/main/java/org/apache/calcite/materialize/MaterializationActor.java @@ -57,7 +57,7 @@ static class Materialization { CalciteSchema.@Nullable TableEntry materializedTable; final String sql; final RelDataType rowType; - final List viewSchemaPath; + final @Nullable List viewSchemaPath; /** Creates a materialization. * @@ -75,7 +75,7 @@ static class Materialization { CalciteSchema.@Nullable TableEntry materializedTable, String sql, RelDataType rowType, - List viewSchemaPath) { + @Nullable List viewSchemaPath) { this.key = key; this.rootSchema = Objects.requireNonNull(rootSchema); Preconditions.checkArgument(rootSchema.isRoot(), "must be root schema"); @@ -91,9 +91,9 @@ static class Materialization { static class QueryKey { final String sql; final CalciteSchema schema; - final List path; + final @Nullable List path; - QueryKey(String sql, CalciteSchema schema, List path) { + QueryKey(String sql, CalciteSchema schema, @Nullable List path) { this.sql = sql; this.schema = schema; this.path = path; @@ -104,7 +104,7 @@ static class QueryKey { || obj instanceof QueryKey && sql.equals(((QueryKey) obj).sql) && schema.equals(((QueryKey) obj).schema) - && path.equals(((QueryKey) obj).path); + && Objects.equals(path, ((QueryKey) obj).path); } @Override public int hashCode() { 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 53fa4d139107..54ce8affb27d 100644 --- a/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java +++ b/core/src/main/java/org/apache/calcite/materialize/MaterializationService.java @@ -54,6 +54,8 @@ import static org.apache.calcite.linq4j.Nullness.castNonNull; +import static java.util.Objects.requireNonNull; + /** * Manages the collection of materialized tables known to the system, * and the process by which they become valid and invalid. @@ -71,10 +73,19 @@ public class MaterializationService { // We prefer rolling up from the table with the fewest rows. final Table t0 = o0.left.getTable(); final Table t1 = o1.left.getTable(); - int c = Double.compare(t0.getStatistic().getRowCount(), - t1.getStatistic().getRowCount()); - if (c != 0) { - return c; + Double rowCount0 = t0.getStatistic().getRowCount(); + Double rowCount1 = t1.getStatistic().getRowCount(); + if (rowCount0 != null && rowCount1 != null) { + int c = Double.compare(rowCount0, rowCount1); + if (c != 0) { + return c; + } + } else if (rowCount0 == null) { + // Unknown is worse than known + return 1; + } else { + // rowCount1 == null => Unknown is worse than known + return -1; } // Tie-break based on table name. return o0.left.name.compareTo(o1.left.name); @@ -88,16 +99,16 @@ private MaterializationService() { /** Defines a new materialization. Returns its key. */ public @Nullable MaterializationKey defineMaterialization(final CalciteSchema schema, - @Nullable TileKey tileKey, String viewSql, List viewSchemaPath, - final String suggestedTableName, boolean create, boolean existing) { + @Nullable TileKey tileKey, String viewSql, @Nullable List viewSchemaPath, + final @Nullable String suggestedTableName, boolean create, boolean existing) { return defineMaterialization(schema, tileKey, viewSql, viewSchemaPath, suggestedTableName, tableFactory, create, existing); } /** Defines a new materialization. Returns its key. */ public @Nullable MaterializationKey defineMaterialization(final CalciteSchema schema, - @Nullable TileKey tileKey, String viewSql, List viewSchemaPath, - String suggestedTableName, TableFactory tableFactory, boolean create, + @Nullable TileKey tileKey, String viewSql, @Nullable List viewSchemaPath, + @Nullable String suggestedTableName, TableFactory tableFactory, boolean create, boolean existing) { final MaterializationActor.QueryKey queryKey = new MaterializationActor.QueryKey(viewSql, schema, viewSchemaPath); @@ -115,6 +126,7 @@ private MaterializationService() { // If the user says the materialization exists, first try to find a table // with the name and if none can be found, lookup a view in the schema if (existing) { + requireNonNull(suggestedTableName, "suggestedTableName"); tableEntry = schema.getTable(suggestedTableName, true); if (tableEntry == null) { tableEntry = schema.getTableBasedOnNullaryFunction(suggestedTableName, true); @@ -173,7 +185,7 @@ private MaterializationService() { * during the recursive SQL that populates a materialization. Otherwise a * materialization would try to create itself to populate itself! */ - public Pair defineTile(Lattice lattice, + public @Nullable Pair defineTile(Lattice lattice, ImmutableBitSet groupSet, List measureList, CalciteSchema schema, boolean create, boolean exact) { return defineTile(lattice, groupSet, measureList, schema, create, exact, @@ -354,7 +366,7 @@ public void removeMaterialization(MaterializationKey key) { */ public interface TableFactory { Table createTable(CalciteSchema schema, String viewSql, - List viewSchemaPath); + @Nullable List viewSchemaPath); } /** @@ -363,7 +375,7 @@ Table createTable(CalciteSchema schema, String viewSql, */ public static class DefaultTableFactory implements TableFactory { @Override public Table createTable(CalciteSchema schema, String viewSql, - List viewSchemaPath) { + @Nullable List viewSchemaPath) { final CalciteConnection connection = CalciteMetaImpl.connect(schema.root(), null); final ImmutableMap map = @@ -379,7 +391,7 @@ public static class DefaultTableFactory implements TableFactory { @Override public Enumerator enumerator() { final DataContext dataContext = Schemas.createDataContext(connection, - calciteSignature.rootSchema.plus()); + requireNonNull(calciteSignature.rootSchema, "rootSchema").plus()); return calciteSignature.enumerable(dataContext).enumerator(); } @@ -398,7 +410,7 @@ public static class DefaultTableFactory implements TableFactory { @Override public Iterator iterator() { final DataContext dataContext = Schemas.createDataContext(connection, - calciteSignature.rootSchema.plus()); + requireNonNull(calciteSignature.rootSchema, "rootSchema").plus()); return calciteSignature.enumerable(dataContext).iterator(); } }); diff --git a/core/src/main/java/org/apache/calcite/model/JsonColumn.java b/core/src/main/java/org/apache/calcite/model/JsonColumn.java index f76050a1aadc..a89827cf0825 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonColumn.java +++ b/core/src/main/java/org/apache/calcite/model/JsonColumn.java @@ -16,6 +16,11 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import static java.util.Objects.requireNonNull; + /** * JSON object representing a column. * @@ -28,7 +33,12 @@ public class JsonColumn { * *

Required, and must be unique within the table. */ - public String name; + public final String name; + + @JsonCreator + public JsonColumn(@JsonProperty(value = "name", required = true) String name) { + this.name = requireNonNull(name, "name"); + } public void accept(ModelHandler handler) { handler.visit(this); diff --git a/core/src/main/java/org/apache/calcite/model/JsonCustomSchema.java b/core/src/main/java/org/apache/calcite/model/JsonCustomSchema.java index 1491a02656e9..dee32b6ec80b 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonCustomSchema.java +++ b/core/src/main/java/org/apache/calcite/model/JsonCustomSchema.java @@ -16,8 +16,16 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.List; import java.util.Map; +import static java.util.Objects.requireNonNull; + /** * JSON schema element that represents a custom schema. * @@ -33,13 +41,26 @@ public class JsonCustomSchema extends JsonMapSchema { * {@link org.apache.calcite.schema.SchemaFactory} and have a public default * constructor. */ - public String factory; + public final String factory; /** Contains attributes to be passed to the factory. * *

May be a JSON object (represented as Map) or null. */ - public Map operand; + public final @Nullable Map operand; + + @JsonCreator + public JsonCustomSchema( + @JsonProperty(value = "name", required = true) String name, + @JsonProperty("path") @Nullable List path, + @JsonProperty("cache") @Nullable Boolean cache, + @JsonProperty("autoLattice") @Nullable Boolean autoLattice, + @JsonProperty(value = "factory", required = true) String factory, + @JsonProperty("operand") @Nullable Map operand) { + super(name, path, cache, autoLattice); + this.factory = requireNonNull(factory, "factory"); + this.operand = operand; + } @Override public void accept(ModelHandler handler) { handler.visit(this); diff --git a/core/src/main/java/org/apache/calcite/model/JsonCustomTable.java b/core/src/main/java/org/apache/calcite/model/JsonCustomTable.java index 2bbab55c6138..ef70381da75e 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonCustomTable.java +++ b/core/src/main/java/org/apache/calcite/model/JsonCustomTable.java @@ -16,8 +16,15 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Map; +import static java.util.Objects.requireNonNull; + /** * Custom table schema element. * @@ -33,13 +40,25 @@ public class JsonCustomTable extends JsonTable { * {@link org.apache.calcite.schema.TableFactory} and have a public default * constructor. */ - public String factory; + public final String factory; /** Contains attributes to be passed to the factory. * *

May be a JSON object (represented as Map) or null. */ - public Map operand; + public final @Nullable Map operand; + + @JsonCreator + public JsonCustomTable( + @JsonProperty(value = "name", required = true) String name, + @JsonProperty("stream") JsonStream stream, + @JsonProperty(value = "factory", required = true) String factory, + @JsonProperty("operand") @Nullable Map operand) { + super(name, stream); + this.factory = requireNonNull(factory, "factory"); + this.operand = operand; + } + @Override public void accept(ModelHandler handler) { handler.visit(this); diff --git a/core/src/main/java/org/apache/calcite/model/JsonFunction.java b/core/src/main/java/org/apache/calcite/model/JsonFunction.java index 716723f578cf..0adf4f886961 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonFunction.java +++ b/core/src/main/java/org/apache/calcite/model/JsonFunction.java @@ -16,8 +16,15 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Function schema element. * @@ -28,13 +35,13 @@ public class JsonFunction { * *

Required. */ - public String name; + public final String name; /** Name of the class that implements this function. * *

Required. */ - public String className; + public final String className; /** Name of the method that implements this function. * @@ -52,13 +59,25 @@ public class JsonFunction { * It also looks for methods "init", "add", "merge", "result", and * if found, creates an aggregate function. */ - public String methodName; + public final @Nullable String methodName; /** Path for resolving this function. * *

Optional. */ - public List path; + public final @Nullable List path; + + @JsonCreator + public JsonFunction( + @JsonProperty("name") String name, + @JsonProperty(value = "className", required = true) String className, + @JsonProperty("methodName") @Nullable String methodName, + @JsonProperty("path") @Nullable List path) { + this.name = name; + this.className = requireNonNull(className, "className"); + this.methodName = methodName; + this.path = path; + } public void accept(ModelHandler handler) { handler.visit(this); diff --git a/core/src/main/java/org/apache/calcite/model/JsonJdbcSchema.java b/core/src/main/java/org/apache/calcite/model/JsonJdbcSchema.java index 036155465dcc..99edce2b22e3 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonJdbcSchema.java +++ b/core/src/main/java/org/apache/calcite/model/JsonJdbcSchema.java @@ -16,6 +16,15 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.List; + +import static java.util.Objects.requireNonNull; + /** * JSON object representing a schema that maps to a JDBC database. * @@ -30,44 +39,65 @@ public class JsonJdbcSchema extends JsonSchema { *

Optional. If not specified, uses whichever class the JDBC * {@link java.sql.DriverManager} chooses. */ - public String jdbcDriver; + public final @Nullable String jdbcDriver; /** The FQN of the {@link org.apache.calcite.sql.SqlDialectFactory} implementation. * *

Optional. If not specified, uses whichever class the JDBC * {@link java.sql.DriverManager} chooses. */ - public String sqlDialectFactory; + public final @Nullable String sqlDialectFactory; /** JDBC connect string, for example "jdbc:mysql://localhost/foodmart". - * - *

Optional. */ - public String jdbcUrl; + public final String jdbcUrl; /** JDBC user name. * *

Optional. */ - public String jdbcUser; + public final @Nullable String jdbcUser; /** JDBC connect string, for example "jdbc:mysql://localhost/foodmart". * *

Optional. */ - public String jdbcPassword; + public final @Nullable String jdbcPassword; /** Name of the initial catalog in the JDBC data source. * *

Optional. */ - public String jdbcCatalog; + public final @Nullable String jdbcCatalog; /** Name of the initial schema in the JDBC data source. * *

Optional. */ - public String jdbcSchema; + public final @Nullable String jdbcSchema; + + @JsonCreator + public JsonJdbcSchema( + @JsonProperty(value = "name", required = true) String name, + @JsonProperty("path") @Nullable List path, + @JsonProperty("cache") @Nullable Boolean cache, + @JsonProperty("autoLattice") @Nullable Boolean autoLattice, + @JsonProperty("jdbcDriver") @Nullable String jdbcDriver, + @JsonProperty("sqlDialectFactory") @Nullable String sqlDialectFactory, + @JsonProperty(value = "jdbcUrl", required = true) String jdbcUrl, + @JsonProperty("jdbcUser") @Nullable String jdbcUser, + @JsonProperty("jdbcPassword") @Nullable String jdbcPassword, + @JsonProperty("jdbcCatalog") @Nullable String jdbcCatalog, + @JsonProperty("jdbcSchema") @Nullable String jdbcSchema) { + super(name, path, cache, autoLattice); + this.jdbcDriver = jdbcDriver; + this.sqlDialectFactory = sqlDialectFactory; + this.jdbcUrl = requireNonNull(jdbcUrl, "jdbcUrl"); + this.jdbcUser = jdbcUser; + this.jdbcPassword = jdbcPassword; + this.jdbcCatalog = jdbcCatalog; + this.jdbcSchema = jdbcSchema; + } @Override public void accept(ModelHandler handler) { handler.visit(this); diff --git a/core/src/main/java/org/apache/calcite/model/JsonLattice.java b/core/src/main/java/org/apache/calcite/model/JsonLattice.java index f05f5fc236ce..0f98143d8d20 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonLattice.java +++ b/core/src/main/java/org/apache/calcite/model/JsonLattice.java @@ -16,11 +16,17 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableList; + import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.checker.nullness.qual.PolyNull; import java.util.ArrayList; import java.util.List; +import java.util.StringJoiner; + +import static java.util.Objects.requireNonNull; /** * Element that describes a star schema and provides a framework for defining, @@ -36,7 +42,7 @@ public class JsonLattice { * *

Required. */ - public @Nullable String name; + public final String name; /** SQL query that defines the lattice. * @@ -47,20 +53,20 @@ public class JsonLattice { * items in the FROM clause, defines the fact table, dimension tables, and * join paths for this lattice. */ - public @Nullable Object sql; + public final Object sql; /** Whether to materialize tiles on demand as queries are executed. * *

Optional; default is true. */ - public boolean auto = true; + public final boolean auto; /** Whether to use an optimization algorithm to suggest and populate an * initial set of tiles. * *

Optional; default is false. */ - public boolean algorithm = false; + public final boolean algorithm; /** Maximum time (in milliseconds) to run the algorithm. * @@ -69,12 +75,12 @@ public class JsonLattice { *

When the timeout is reached, Calcite uses the best result that has * been obtained so far. */ - public long algorithmMaxMillis = -1; + public final long algorithmMaxMillis; /** Estimated number of rows. * *

If null, Calcite will a query to find the real value. */ - public @Nullable Double rowCountEstimate; + public final @Nullable Double rowCountEstimate; /** Name of a class that provides estimates of the number of distinct values * in each column. @@ -87,7 +93,7 @@ public class JsonLattice { * *

If not set, Calcite will generate and execute a SQL query to find the * real value, and cache the results. */ - public @Nullable String statisticProvider; + public final @Nullable String statisticProvider; /** List of materialized aggregates to create up front. */ public final List tiles = new ArrayList<>(); @@ -98,7 +104,28 @@ public class JsonLattice { * *

Optional. The default list is just "count(*)". */ - public @Nullable List defaultMeasures; + public final List defaultMeasures; + + @JsonCreator + public JsonLattice( + @JsonProperty(value = "name", required = true) String name, + @JsonProperty(value = "sql", required = true) Object sql, + @JsonProperty("auto") @Nullable Boolean auto, + @JsonProperty("algorithm") @Nullable Boolean algorithm, + @JsonProperty("algorithmMaxMillis") @Nullable Long algorithmMaxMillis, + @JsonProperty("rowCountEstimate") @Nullable Double rowCountEstimate, + @JsonProperty("statisticProvider") @Nullable String statisticProvider, + @JsonProperty("defaultMeasures") @Nullable List defaultMeasures) { + this.name = requireNonNull(name, "name"); + this.sql = requireNonNull(sql, "sql"); + this.auto = auto == null || auto; + this.algorithm = algorithm != null && algorithm; + this.algorithmMaxMillis = algorithmMaxMillis == null ? -1 : algorithmMaxMillis; + this.rowCountEstimate = rowCountEstimate; + this.statisticProvider = statisticProvider; + this.defaultMeasures = defaultMeasures == null + ? ImmutableList.of(new JsonMeasure("count", null)) : defaultMeasures; + } public void accept(ModelHandler handler) { handler.visit(this); @@ -116,22 +143,22 @@ public String getSql() { /** Converts a string or a list of strings to a string. The list notation * is a convenient way of writing long multi-line strings in JSON. */ - static @PolyNull String toString(@PolyNull Object o) { - return o == null ? null - : o instanceof String ? (String) o - : concatenate((List) o); + static String toString(Object o) { + requireNonNull(o, "argument must not be null"); + //noinspection unchecked + return o instanceof String ? (String) o + : concatenate((List) o); } /** Converts a list of strings into a multi-line string. */ - private static String concatenate(List list) { - final StringBuilder buf = new StringBuilder(); + private static String concatenate(List list) { + final StringJoiner buf = new StringJoiner("\n", "", "\n"); for (Object o : list) { if (!(o instanceof String)) { throw new RuntimeException( "each element of a string list must be a string; found: " + o); } - buf.append((String) o); - buf.append("\n"); + buf.add((String) o); } return buf.toString(); } diff --git a/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java b/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java index 1b8300df65a8..98d06754ae1b 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java +++ b/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java @@ -16,6 +16,11 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.List; @@ -46,6 +51,15 @@ public class JsonMapSchema extends JsonSchema { */ public final List functions = new ArrayList<>(); + @JsonCreator + public JsonMapSchema( + @JsonProperty(value = "name", required = true) String name, + @JsonProperty("path") @Nullable List path, + @JsonProperty("cache") @Nullable Boolean cache, + @JsonProperty("autoLattice") @Nullable Boolean autoLattice) { + super(name, path, cache, autoLattice); + } + @Override public void accept(ModelHandler handler) { handler.visit(this); } diff --git a/core/src/main/java/org/apache/calcite/model/JsonMaterialization.java b/core/src/main/java/org/apache/calcite/model/JsonMaterialization.java index 59c0c2f422b9..55969be47f5a 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonMaterialization.java +++ b/core/src/main/java/org/apache/calcite/model/JsonMaterialization.java @@ -16,8 +16,15 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Element that describes how a table is a materialization of a query. * @@ -26,17 +33,29 @@ * @see JsonRoot Description of schema elements */ public class JsonMaterialization { - public String view; - public String table; + public final @Nullable String view; + public final @Nullable String table; /** SQL query that defines the materialization. * *

Must be a string or a list of strings (which are concatenated into a * multi-line SQL string, separated by newlines). */ - public Object sql; + public final Object sql; - public List viewSchemaPath; + public final @Nullable List viewSchemaPath; + + @JsonCreator + public JsonMaterialization( + @JsonProperty("view") @Nullable String view, + @JsonProperty("table") @Nullable String table, + @JsonProperty(value = "sql", required = true) Object sql, + @JsonProperty("viewSchemaPath") @Nullable List viewSchemaPath) { + this.view = view; + this.table = table; + this.sql = requireNonNull(sql, "sql"); + this.viewSchemaPath = viewSchemaPath; + } public void accept(ModelHandler handler) { handler.visit(this); diff --git a/core/src/main/java/org/apache/calcite/model/JsonMeasure.java b/core/src/main/java/org/apache/calcite/model/JsonMeasure.java index 37737cc97486..8485eb35f127 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonMeasure.java +++ b/core/src/main/java/org/apache/calcite/model/JsonMeasure.java @@ -16,6 +16,13 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import static java.util.Objects.requireNonNull; + /** * An aggregate function applied to a column (or columns) of a lattice. * @@ -31,7 +38,7 @@ public class JsonMeasure { *

Required. Usually {@code count}, {@code sum}, * {@code min}, {@code max}. */ - public String agg; + public final String agg; /** Arguments to the measure. * @@ -49,7 +56,15 @@ public class JsonMeasure { * that each column you intend to use as a measure has a unique name within * the lattice (using "{@code AS alias}" if necessary). */ - public Object args; + public final @Nullable Object args; + + @JsonCreator + public JsonMeasure( + @JsonProperty(value = "agg", required = true) String agg, + @JsonProperty("args") @Nullable Object args) { + this.agg = requireNonNull(agg, "agg"); + this.args = args; + } public void accept(ModelHandler modelHandler) { modelHandler.visit(this); diff --git a/core/src/main/java/org/apache/calcite/model/JsonRoot.java b/core/src/main/java/org/apache/calcite/model/JsonRoot.java index feca1e3ae455..f35790c6a495 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonRoot.java +++ b/core/src/main/java/org/apache/calcite/model/JsonRoot.java @@ -16,11 +16,16 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + import org.checkerframework.checker.nullness.qual.Nullable; import java.util.ArrayList; import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Root schema element. * @@ -52,7 +57,7 @@ */ public class JsonRoot { /** Schema model version number. Required, must have value "1.0". */ - public @Nullable String version; + public final String version; /** Name of the schema that will become the default schema for connections * to Calcite that use this model. @@ -60,11 +65,19 @@ public class JsonRoot { *

Optional, case-sensitive. If specified, there must be a schema in this * model with this name. */ - public @Nullable String defaultSchema; + public final @Nullable String defaultSchema; /** List of schema elements. * *

The list may be empty. */ public final List schemas = new ArrayList<>(); + + @JsonCreator + public JsonRoot( + @JsonProperty(value = "version", required = true) String version, + @JsonProperty("defaultSchema") @Nullable String defaultSchema) { + this.version = requireNonNull(version, "version"); + this.defaultSchema = defaultSchema; + } } diff --git a/core/src/main/java/org/apache/calcite/model/JsonSchema.java b/core/src/main/java/org/apache/calcite/model/JsonSchema.java index 3e4bb865b731..9b1a7c0396dc 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonSchema.java +++ b/core/src/main/java/org/apache/calcite/model/JsonSchema.java @@ -46,7 +46,7 @@ public abstract class JsonSchema { * * @see JsonRoot#defaultSchema */ - public @Nullable String name; + public final String name; /** SQL path that is used to resolve functions used in this schema. * @@ -61,7 +61,7 @@ public abstract class JsonSchema { * '/lib'. Most schemas are at the top level, and for these you can use a * string. */ - public @Nullable List path; + public final @Nullable List path; /** * List of tables in this schema that are materializations of queries. @@ -88,11 +88,19 @@ public abstract class JsonSchema { * not affected by this caching mechanism. They always appear in the schema * immediately, and are never flushed.

*/ - public @Nullable Boolean cache; + public final @Nullable Boolean cache; /** Whether to create lattices in this schema based on queries occurring in * other schemas. Default value is {@code false}. */ - public @Nullable Boolean autoLattice; + public final @Nullable Boolean autoLattice; + + protected JsonSchema(String name, @Nullable List path, @Nullable Boolean cache, + @Nullable Boolean autoLattice) { + this.name = name; + this.path = path; + this.cache = cache; + this.autoLattice = autoLattice; + } public abstract void accept(ModelHandler handler); diff --git a/core/src/main/java/org/apache/calcite/model/JsonStream.java b/core/src/main/java/org/apache/calcite/model/JsonStream.java index bc9ee484d273..886fd9143d79 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonStream.java +++ b/core/src/main/java/org/apache/calcite/model/JsonStream.java @@ -16,6 +16,11 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Information about whether a table allows streaming. * @@ -29,11 +34,19 @@ public class JsonStream { * *

Optional; default true. */ - public boolean stream = true; + public final boolean stream; /** Whether the history of the table is available. * *

Optional; default false. */ - public boolean history = false; + public final boolean history; + + @JsonCreator + public JsonStream( + @JsonProperty("stream") @Nullable Boolean stream, + @JsonProperty("history") @Nullable Boolean history) { + this.stream = stream == null || stream; + this.history = history != null && history; + } } diff --git a/core/src/main/java/org/apache/calcite/model/JsonTable.java b/core/src/main/java/org/apache/calcite/model/JsonTable.java index 3fb80be18b2a..f6d977b54c0a 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonTable.java +++ b/core/src/main/java/org/apache/calcite/model/JsonTable.java @@ -19,9 +19,13 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Table schema element. * @@ -41,7 +45,7 @@ public abstract class JsonTable { * *

Required. Must be unique within the schema. */ - public String name; + public final String name; /** Definition of the columns of this table. * @@ -52,7 +56,12 @@ public abstract class JsonTable { /** Information about whether the table can be streamed, and if so, whether * the history of the table is also available. */ - public JsonStream stream; + public final @Nullable JsonStream stream; + + protected JsonTable(String name, @Nullable JsonStream stream) { + this.name = requireNonNull(name, "name"); + this.stream = stream; + } public abstract void accept(ModelHandler handler); } diff --git a/core/src/main/java/org/apache/calcite/model/JsonTile.java b/core/src/main/java/org/apache/calcite/model/JsonTile.java index c007f05d9fb2..33e087096f1d 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonTile.java +++ b/core/src/main/java/org/apache/calcite/model/JsonTile.java @@ -16,6 +16,12 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableList; + +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.List; @@ -46,7 +52,13 @@ public class JsonTile { * *

If not specified, uses {@link JsonLattice#defaultMeasures}. */ - public List measures; + public final List measures; + + @JsonCreator + public JsonTile(@JsonProperty("measures") @Nullable List measures) { + this.measures = measures == null + ? ImmutableList.of(new JsonMeasure("count", null)) : measures; + } public void accept(ModelHandler handler) { handler.visit(this); diff --git a/core/src/main/java/org/apache/calcite/model/JsonType.java b/core/src/main/java/org/apache/calcite/model/JsonType.java index 3b65a7e6b8d2..c7475a7686df 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonType.java +++ b/core/src/main/java/org/apache/calcite/model/JsonType.java @@ -16,11 +16,16 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + import org.checkerframework.checker.nullness.qual.Nullable; import java.util.ArrayList; import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Type schema element. * @@ -33,17 +38,24 @@ public class JsonType { * *

Required. */ - @SuppressWarnings("NotNullFieldNotInitialized") - public String name; + public final String name; /** Type if this is not a struct. */ - public @Nullable String type; + public final @Nullable String type; /** Definition of the attributes of this type. */ public final List attributes = new ArrayList<>(); + @JsonCreator + public JsonType( + @JsonProperty(value = "name", required = true) String name, + @JsonProperty("type") @Nullable String type) { + this.name = requireNonNull(name, "name"); + this.type = type; + } + public void accept(ModelHandler handler) { handler.visit(this); } diff --git a/core/src/main/java/org/apache/calcite/model/JsonTypeAttribute.java b/core/src/main/java/org/apache/calcite/model/JsonTypeAttribute.java index 8ce2a2883c8a..b5003ea55e90 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonTypeAttribute.java +++ b/core/src/main/java/org/apache/calcite/model/JsonTypeAttribute.java @@ -16,6 +16,11 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import static java.util.Objects.requireNonNull; + /** * JSON object representing a type attribute. */ @@ -24,11 +29,19 @@ public class JsonTypeAttribute { * *

Required. */ - public String name; + public final String name; /** Type of this attribute. * *

Required. */ - public String type; + public final String type; + + @JsonCreator + public JsonTypeAttribute( + @JsonProperty(value = "name", required = true) String name, + @JsonProperty(value = "type", required = true) String type) { + this.name = requireNonNull(name, "name"); + this.type = requireNonNull(type, "type"); + } } diff --git a/core/src/main/java/org/apache/calcite/model/JsonView.java b/core/src/main/java/org/apache/calcite/model/JsonView.java index 0a8b9a650653..ff4e98b1bbdd 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonView.java +++ b/core/src/main/java/org/apache/calcite/model/JsonView.java @@ -16,9 +16,13 @@ */ package org.apache.calcite.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + import org.checkerframework.checker.nullness.qual.Nullable; import java.util.List; +import java.util.Objects; /** * View schema element. @@ -62,13 +66,13 @@ public class JsonView extends JsonTable { *

Must be a string or a list of strings (which are concatenated into a * multi-line SQL string, separated by newlines). */ - public @Nullable Object sql; + public final Object sql; /** Schema name(s) to use when resolving query. * *

If not specified, defaults to current schema. */ - public @Nullable List path; + public final @Nullable List path; /** Whether this view should allow INSERT requests. * @@ -82,7 +86,20 @@ public class JsonView extends JsonTable { * *

The default value is {@code null}. */ - public @Nullable Boolean modifiable; + public final @Nullable Boolean modifiable; + + @JsonCreator + public JsonView( + @JsonProperty(value = "name", required = true) String name, + @JsonProperty("steram") JsonStream stream, + @JsonProperty(value = "sql", required = true) Object sql, + @JsonProperty("path") @Nullable List path, + @JsonProperty("modifiable") @Nullable Boolean modifiable) { + super(name, stream); + this.sql = Objects.requireNonNull(sql, "sql"); + this.path = path; + this.modifiable = modifiable; + } @Override public void accept(ModelHandler handler) { handler.visit(this); diff --git a/core/src/main/java/org/apache/calcite/model/ModelHandler.java b/core/src/main/java/org/apache/calcite/model/ModelHandler.java index 4093fdca0be5..04758640c751 100644 --- a/core/src/main/java/org/apache/calcite/model/ModelHandler.java +++ b/core/src/main/java/org/apache/calcite/model/ModelHandler.java @@ -55,7 +55,6 @@ import java.io.File; import java.io.IOException; -import java.lang.reflect.Field; import java.sql.SQLException; import java.util.ArrayDeque; import java.util.Collections; @@ -63,9 +62,10 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Objects; import javax.sql.DataSource; +import static java.util.Objects.requireNonNull; + /** * Reads a model and creates schema objects accordingly. */ @@ -77,7 +77,8 @@ public class ModelHandler { private static final ObjectMapper YAML_MAPPER = new YAMLMapper(); private final CalciteConnection connection; - private final Deque> schemaStack = new ArrayDeque<>(); + private final Deque> schemaStack = + new ArrayDeque<>(); private final String modelUri; Lattice.@Nullable Builder latticeBuilder; Lattice.@Nullable TileBuilder tileBuilder; @@ -128,7 +129,7 @@ public static void create(SchemaPlus schema, String functionName, * can be called without using quotes */ public static void addFunctions(SchemaPlus schema, @Nullable String functionName, - List path, String className, String methodName, boolean upCase) { + List path, String className, @Nullable String methodName, boolean upCase) { final Class clazz; try { clazz = Class.forName(className); @@ -136,11 +137,20 @@ public static void addFunctions(SchemaPlus schema, @Nullable String functionName throw new RuntimeException("UDF class '" + className + "' not found"); } + String methodNameOrDefault = Util.first(methodName, "eval"); + String actualFunctionName; + if (functionName != null) { + actualFunctionName = functionName; + } else { + actualFunctionName = methodNameOrDefault; + } + if (upCase) { + actualFunctionName = actualFunctionName.toUpperCase(Locale.ROOT); + } final TableFunction tableFunction = - TableFunctionImpl.create(clazz, Util.first(methodName, "eval")); + TableFunctionImpl.create(clazz, methodNameOrDefault); if (tableFunction != null) { - schema.add( - Objects.requireNonNull(functionName, "functionName"), + schema.add(Util.first(functionName, methodNameOrDefault), tableFunction); return; } @@ -148,7 +158,7 @@ public static void addFunctions(SchemaPlus schema, @Nullable String functionName // method. final TableMacro macro = TableMacroImpl.create(clazz); if (macro != null) { - schema.add(functionName, macro); + schema.add(actualFunctionName, macro); return; } if (methodName != null && methodName.equals("*")) { @@ -163,24 +173,16 @@ public static void addFunctions(SchemaPlus schema, @Nullable String functionName return; } else { final ScalarFunction function = - ScalarFunctionImpl.create(clazz, Util.first(methodName, "eval")); + ScalarFunctionImpl.create(clazz, methodNameOrDefault); if (function != null) { - final String name; - if (functionName != null) { - name = functionName; - } else if (upCase) { - name = methodName.toUpperCase(Locale.ROOT); - } else { - name = methodName; - } - schema.add(name, function); + schema.add(actualFunctionName, function); return; } } if (methodName == null) { final AggregateFunction aggFunction = AggregateFunctionImpl.create(clazz); if (aggFunction != null) { - schema.add(functionName, aggFunction); + schema.add(actualFunctionName, aggFunction); return; } } @@ -190,32 +192,14 @@ public static void addFunctions(SchemaPlus schema, @Nullable String functionName + "'initAdd', 'merge' and 'result' methods."); } - private void checkRequiredAttributes(Object json, String... attributeNames) { - for (String attributeName : attributeNames) { - try { - final Class c = json.getClass(); - final Field f = c.getField(attributeName); - final Object o = f.get(json); - if (o == null) { - throw new RuntimeException("Field '" + attributeName - + "' is required in " + c.getSimpleName()); - } - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new RuntimeException("while accessing field " + attributeName, - e); - } - } - } - public void visit(JsonRoot jsonRoot) { - checkRequiredAttributes(jsonRoot, "version"); final Pair<@Nullable String, SchemaPlus> pair = Pair.of(null, connection.getRootSchema()); schemaStack.push(pair); for (JsonSchema schema : jsonRoot.schemas) { schema.accept(this); } - final Pair<@Nullable String, SchemaPlus> p = schemaStack.pop(); + final Pair p = schemaStack.pop(); assert p == pair; if (jsonRoot.defaultSchema != null) { try { @@ -227,7 +211,6 @@ public void visit(JsonRoot jsonRoot) { } public void visit(JsonMapSchema jsonSchema) { - checkRequiredAttributes(jsonSchema, "name"); final SchemaPlus parentSchema = currentMutableSchema("schema"); final SchemaPlus schema = parentSchema.add(jsonSchema.name, new AbstractSchema()); @@ -275,14 +258,13 @@ private void populateSchema(JsonSchema jsonSchema, SchemaPlus schema) { final Pair pair = Pair.of(jsonSchema.name, schema); schemaStack.push(pair); jsonSchema.visitChildren(this); - final Pair p = schemaStack.pop(); + final Pair p = schemaStack.pop(); assert p == pair; } public void visit(JsonCustomSchema jsonSchema) { try { final SchemaPlus parentSchema = currentMutableSchema("sub-schema"); - checkRequiredAttributes(jsonSchema, "name", "factory"); final SchemaFactory schemaFactory = AvaticaUtils.instantiatePlugin(SchemaFactory.class, jsonSchema.factory); @@ -297,8 +279,8 @@ public void visit(JsonCustomSchema jsonSchema) { } /** Adds extra entries to an operand to a custom schema. */ - protected Map operandMap(JsonSchema jsonSchema, - Map operand) { + protected Map operandMap(@Nullable JsonSchema jsonSchema, + @Nullable Map operand) { if (operand == null) { return ImmutableMap.of(); } @@ -336,7 +318,6 @@ protected Map operandMap(JsonSchema jsonSchema, } public void visit(JsonJdbcSchema jsonSchema) { - checkRequiredAttributes(jsonSchema, "name"); final SchemaPlus parentSchema = currentMutableSchema("jdbc schema"); final DataSource dataSource = JdbcSchema.dataSource(jsonSchema.jdbcUrl, @@ -361,7 +342,6 @@ public void visit(JsonJdbcSchema jsonSchema) { public void visit(JsonMaterialization jsonMaterialization) { try { - checkRequiredAttributes(jsonMaterialization, "sql"); final SchemaPlus schema = currentSchema(); if (!schema.isMutable()) { throw new RuntimeException( @@ -395,7 +375,6 @@ public void visit(JsonMaterialization jsonMaterialization) { public void visit(JsonLattice jsonLattice) { try { - checkRequiredAttributes(jsonLattice, "name", "sql"); final SchemaPlus schema = currentSchema(); if (!schema.isMutable()) { throw new RuntimeException("Cannot define lattice; parent schema '" @@ -422,12 +401,6 @@ public void visit(JsonLattice jsonLattice) { private void populateLattice(JsonLattice jsonLattice, Lattice.Builder latticeBuilder) { - // By default, the default measure list is just {count(*)}. - if (jsonLattice.defaultMeasures == null) { - final JsonMeasure countMeasure = new JsonMeasure(); - countMeasure.agg = "count"; - jsonLattice.defaultMeasures = ImmutableList.of(countMeasure); - } assert this.latticeBuilder == null; this.latticeBuilder = latticeBuilder; jsonLattice.visitChildren(this); @@ -436,7 +409,6 @@ private void populateLattice(JsonLattice jsonLattice, public void visit(JsonCustomTable jsonTable) { try { - checkRequiredAttributes(jsonTable, "name", "factory"); final SchemaPlus schema = currentMutableSchema("table"); final TableFactory tableFactory = AvaticaUtils.instantiatePlugin(TableFactory.class, @@ -454,12 +426,10 @@ public void visit(JsonCustomTable jsonTable) { } public void visit(JsonColumn jsonColumn) { - checkRequiredAttributes(jsonColumn, "name"); } public void visit(JsonView jsonView) { try { - checkRequiredAttributes(jsonView, "name"); final SchemaPlus schema = currentMutableSchema("view"); final List path = Util.first(jsonView.path, currentSchemaPath()); final List viewPath = ImmutableList.builder().addAll(path) @@ -473,15 +443,19 @@ public void visit(JsonView jsonView) { } private List currentSchemaPath() { - return Collections.singletonList(schemaStack.peek().left); + return Collections.singletonList(currentSchemaName()); + } + + private Pair nameAndSchema() { + return requireNonNull(schemaStack.peek(), "schemaStack.peek()"); } private SchemaPlus currentSchema() { - return schemaStack.peek().right; + return nameAndSchema().right; } private String currentSchemaName() { - return schemaStack.peek().left; + return requireNonNull(nameAndSchema().left, "currentSchema.name"); } private SchemaPlus currentMutableSchema(String elementType) { @@ -494,20 +468,24 @@ private SchemaPlus currentMutableSchema(String elementType) { } public void visit(final JsonType jsonType) { - checkRequiredAttributes(jsonType, "name"); try { final SchemaPlus schema = currentMutableSchema("type"); schema.add(jsonType.name, typeFactory -> { if (jsonType.type != null) { - return typeFactory.createSqlType(SqlTypeName.get(jsonType.type)); + return typeFactory.createSqlType( + requireNonNull(SqlTypeName.get(jsonType.type), + () -> "SqlTypeName.get for " + jsonType.type)); } else { final RelDataTypeFactory.Builder builder = typeFactory.builder(); for (JsonTypeAttribute jsonTypeAttribute : jsonType.attributes) { - final SqlTypeName typeName = - SqlTypeName.get(jsonTypeAttribute.type); + final SqlTypeName typeName = requireNonNull( + SqlTypeName.get(jsonTypeAttribute.type), + () -> "SqlTypeName.get for " + jsonTypeAttribute.type); RelDataType type = typeFactory.createSqlType(typeName); if (type == null) { - type = currentSchema().getType(jsonTypeAttribute.type) + type = requireNonNull(currentSchema().getType(jsonTypeAttribute.type), + () -> "type " + jsonTypeAttribute.type + " is not found in schema " + + currentSchemaName()) .apply(typeFactory); } builder.add(jsonTypeAttribute.name, type); @@ -522,7 +500,6 @@ public void visit(final JsonType jsonType) { public void visit(JsonFunction jsonFunction) { // "name" is not required - a class can have several functions - checkRequiredAttributes(jsonFunction, "className"); try { final SchemaPlus schema = currentMutableSchema("function"); final List path = @@ -535,7 +512,6 @@ public void visit(JsonFunction jsonFunction) { } public void visit(JsonMeasure jsonMeasure) { - checkRequiredAttributes(jsonMeasure, "agg"); assert latticeBuilder != null; final boolean distinct = false; // no distinct field in JsonMeasure.yet final Lattice.Measure measure = @@ -552,16 +528,17 @@ public void visit(JsonMeasure jsonMeasure) { public void visit(JsonTile jsonTile) { assert tileBuilder == null; - tileBuilder = Lattice.Tile.builder(); + Lattice.TileBuilder tileBuilder = this.tileBuilder = Lattice.Tile.builder(); for (JsonMeasure jsonMeasure : jsonTile.measures) { jsonMeasure.accept(this); } + Lattice.Builder latticeBuilder = requireNonNull(this.latticeBuilder, "latticeBuilder"); for (Object dimension : jsonTile.dimensions) { final Lattice.Column column = latticeBuilder.resolveColumn(dimension); tileBuilder.addDimension(column); } latticeBuilder.addTile(tileBuilder.build()); - tileBuilder = null; + this.tileBuilder = null; } /** Extra operands automatically injected into a diff --git a/core/src/main/java/org/apache/calcite/plan/Contexts.java b/core/src/main/java/org/apache/calcite/plan/Contexts.java index c919912c5190..bf7adb13d9e4 100644 --- a/core/src/main/java/org/apache/calcite/plan/Contexts.java +++ b/core/src/main/java/org/apache/calcite/plan/Contexts.java @@ -120,7 +120,7 @@ private static class WrapContext implements Context { this.target = Objects.requireNonNull(target); } - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { if (clazz.isInstance(target)) { return clazz.cast(target); } @@ -130,7 +130,7 @@ private static class WrapContext implements Context { /** Empty context. */ static class EmptyContext implements Context { - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { return null; } } @@ -146,7 +146,7 @@ private static final class ChainContext implements Context { } } - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { for (Context context : contexts) { final T t = context.unwrap(clazz); if (t != 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 c58991587015..785703f21f46 100644 --- a/core/src/main/java/org/apache/calcite/plan/ConventionTraitDef.java +++ b/core/src/main/java/org/apache/calcite/plan/ConventionTraitDef.java @@ -36,6 +36,8 @@ import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Definition of the convention trait. * A new set of conversion information is created for @@ -133,7 +135,8 @@ private ConventionTraitDef() { final RelMetadataQuery mq = rel.getCluster().getMetadataQuery(); final ConversionData conversionData = getConversionData(planner); - final Convention fromConvention = rel.getConvention(); + final Convention fromConvention = requireNonNull(rel.getConvention(), + () -> "convention is null for rel " + rel); List> conversionPaths = conversionData.getPaths(fromConvention, toConvention); @@ -146,7 +149,8 @@ private ConventionTraitDef() { RelNode converted = rel; Convention previous = null; for (Convention arc : conversionPath) { - if (planner.getCost(converted, mq).isInfinite() + RelOptCost cost = planner.getCost(converted, mq); + if ((cost == null || cost.isInfinite()) && !allowInfiniteCostConverters) { continue loop; } diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java b/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java index 2c2af1fb70e9..efd9aec68ef0 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptAbstractTable.java @@ -80,15 +80,15 @@ public String getName() { } // Override to define collations. - @Override public List getCollationList() { + @Override public @Nullable List getCollationList() { return Collections.emptyList(); } - @Override public RelDistribution getDistribution() { + @Override public @Nullable RelDistribution getDistribution() { return RelDistributions.BROADCAST_DISTRIBUTED; } - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { return clazz.isInstance(this) ? clazz.cast(this) : null; @@ -100,12 +100,12 @@ public String getName() { } // Override to get unique keys - @Override public List getKeys() { + @Override public @Nullable List getKeys() { return Collections.emptyList(); } // Override to define foreign keys - @Override public List getReferentialConstraints() { + @Override public @Nullable List getReferentialConstraints() { return Collections.emptyList(); } diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java b/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java index 8d06739ffcc1..0342ca08c38d 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptPredicateList.java @@ -26,6 +26,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Collection; import java.util.Objects; @@ -120,6 +122,21 @@ public static RelOptPredicateList of(RexBuilder rexBuilder, return of(rexBuilder, pulledUpPredicatesList, EMPTY_LIST, EMPTY_LIST); } + /** + * Returns true if given predicate list is empty. + * @param value input predicate list + * @return true if all the predicates are empty or if the argument is null + */ + public static boolean isEmpty(@Nullable RelOptPredicateList value) { + if (value == null || value == EMPTY) { + return true; + } + return value.constantMap.isEmpty() + && value.leftInferredPredicates.isEmpty() + && value.rightInferredPredicates.isEmpty() + && value.pulledUpPredicates.isEmpty(); + } + /** Creates a RelOptPredicateList for a join. * * @param rexBuilder Rex builder diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptTable.java b/core/src/main/java/org/apache/calcite/plan/RelOptTable.java index a317f0cbd87c..1e9929973e75 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptTable.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptTable.java @@ -62,7 +62,7 @@ public interface RelOptTable extends Wrapper { /** * Returns the {@link RelOptSchema} this table belongs to. */ - RelOptSchema getRelOptSchema(); + @Nullable RelOptSchema getRelOptSchema(); /** * Converts this table into a {@link RelNode relational expression}. @@ -83,7 +83,7 @@ public interface RelOptTable extends Wrapper { * * @see RelMetadataQuery#collations(RelNode) */ - List getCollationList(); + @Nullable List getCollationList(); /** * Returns a description of the physical distribution of the rows @@ -91,7 +91,7 @@ public interface RelOptTable extends Wrapper { * * @see RelMetadataQuery#distribution(RelNode) */ - RelDistribution getDistribution(); + @Nullable RelDistribution getDistribution(); /** * Returns whether the given columns are a key or a superset of a unique key @@ -106,13 +106,13 @@ public interface RelOptTable extends Wrapper { * Returns a list of unique keys, empty list if no key exist, * the result should be consistent with {@code isKey}. */ - List getKeys(); + @Nullable List getKeys(); /** * Returns the referential constraints existing for this table. These constraints * are represented over other tables using {@link RelReferentialConstraint} nodes. */ - List getReferentialConstraints(); + @Nullable List getReferentialConstraints(); /** * Generates code for this table. 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 ad583938a235..f342c7469a40 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java @@ -2865,7 +2865,7 @@ private static RexNode shiftFilter( */ public static void splitFilters( ImmutableBitSet childBitmap, - RexNode predicate, + @Nullable RexNode predicate, List pushable, List notPushable) { // for each filter, if the filter only references the child inputs, @@ -3122,7 +3122,7 @@ public static boolean contains(RelNode ancestor, final RelNode target) { try { new RelVisitor() { @Override public void visit(RelNode node, int ordinal, - RelNode parent) { + @Nullable RelNode parent) { if (node == target) { throw Util.FoundOne.NULL; } @@ -3798,7 +3798,7 @@ private static boolean containsNullableFields(RelNode r) { return false; } final RelOptPredicateList predicates = mq.getPulledUpPredicates(r); - if (predicates == null || predicates.pulledUpPredicates.isEmpty()) { + if (RelOptPredicateList.isEmpty(predicates)) { // We have no predicates, so cannot deduce that any of the fields // declared NULL are really NOT NULL. return true; 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 7abbbb9133b1..b0f1ee717d01 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelRule.java +++ b/core/src/main/java/org/apache/calcite/plan/RelRule.java @@ -130,7 +130,7 @@ public interface Config { RelOptRule toRule(); /** Casts this configuration to another type, usually a sub-class. */ - default T as(Class class_) { + default T as(Class class_) { return ImmutableBeans.copy(class_, this); } 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 6e54f3068142..6b0592116b1a 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java +++ b/core/src/main/java/org/apache/calcite/plan/RelTraitSet.java @@ -245,7 +245,7 @@ public RelTraitSet replace(RelTraitDef def, * function. */ @CheckReturnValue public RelTraitSet replaceIfs(RelTraitDef def, - Supplier> traitSupplier) { + Supplier> traitSupplier) { int index = findIndex(def); if (index < 0) { return this; // trait is not enabled; ignore it diff --git a/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java b/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java index 70c14bc3e151..a3ceb8a09a6c 100644 --- a/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java +++ b/core/src/main/java/org/apache/calcite/plan/RexImplicationChecker.java @@ -307,15 +307,15 @@ private boolean isSatisfiable(RexNode second, @Nullable DataContext dataValues) */ private boolean checkSupport(InputUsageFinder firstUsageFinder, InputUsageFinder secondUsageFinder) { - final Map> firstUsageMap = + final Map> firstUsageMap = firstUsageFinder.usageMap; - final Map> secondUsageMap = + final Map> secondUsageMap = secondUsageFinder.usageMap; - for (Map.Entry> entry + for (Map.Entry> entry : secondUsageMap.entrySet()) { - final InputRefUsage secondUsage = entry.getValue(); - final List> secondUsageList = secondUsage.usageList; + final InputRefUsage secondUsage = entry.getValue(); + final List> secondUsageList = secondUsage.usageList; final int secondLen = secondUsageList.size(); if (secondUsage.usageCount != secondLen || secondLen > 2) { @@ -337,9 +337,9 @@ private boolean checkSupport(InputUsageFinder firstUsageFinder, final SqlKind fKind = firstUsageList.get(0).getKey().getKind(); final SqlKind sKind = secondUsageList.get(0).getKey().getKind(); final SqlKind fKind2 = - (firstUsageList.size() == 2) ? firstUsageList.get(1).getKey().getKind() : null; + firstLen == 2 ? firstUsageList.get(1).getKey().getKind() : null; final SqlKind sKind2 = - (secondUsageList.size() == 2) ? secondUsageList.get(1).getKey().getKind() : null; + secondLen == 2 ? secondUsageList.get(1).getKey().getKind() : null; if (firstLen == 2 && secondLen == 2 && !(isEquivalentOp(fKind, sKind) && isEquivalentOp(fKind2, sKind2)) @@ -436,7 +436,7 @@ private boolean validate(RexNode first, RexNode second) { * */ private static class InputUsageFinder extends RexVisitorImpl { - final Map> usageMap = + final Map> usageMap = new HashMap<>(); InputUsageFinder() { @@ -444,7 +444,7 @@ private static class InputUsageFinder extends RexVisitorImpl { } @Override public Void visitInputRef(RexInputRef inputRef) { - InputRefUsage inputRefUse = getUsageMap(inputRef); + InputRefUsage inputRefUse = getUsageMap(inputRef); inputRefUse.usageCount++; return null; } @@ -498,15 +498,15 @@ private SqlOperator reverse(SqlOperator op) { } private void updateUsage(SqlOperator op, RexInputRef inputRef, - RexNode literal) { - final InputRefUsage inputRefUse = + @Nullable RexNode literal) { + final InputRefUsage inputRefUse = getUsageMap(inputRef); - Pair use = Pair.of(op, literal); + Pair use = Pair.of(op, literal); inputRefUse.usageList.add(use); } - private InputRefUsage getUsageMap(RexInputRef rex) { - InputRefUsage inputRefUse = usageMap.get(rex); + private InputRefUsage getUsageMap(RexInputRef rex) { + InputRefUsage inputRefUse = usageMap.get(rex); if (inputRefUse == null) { inputRefUse = new InputRefUsage<>(); usageMap.put(rex, inputRefUse); diff --git a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java index 1fc7f5292ba8..9a15674ea05b 100644 --- a/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java +++ b/core/src/main/java/org/apache/calcite/plan/SubstitutionVisitor.java @@ -41,7 +41,6 @@ import org.apache.calcite.rex.RexBuilder; import org.apache.calcite.rex.RexCall; import org.apache.calcite.rex.RexExecutor; -import org.apache.calcite.rex.RexExecutorImpl; import org.apache.calcite.rex.RexInputRef; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexLocalRef; @@ -82,13 +81,14 @@ import java.util.List; import java.util.Map; import java.util.NavigableMap; -import java.util.Objects; import java.util.Set; import java.util.TreeMap; import static org.apache.calcite.rex.RexUtil.andNot; import static org.apache.calcite.rex.RexUtil.removeAll; +import static java.util.Objects.requireNonNull; + /** * Substitutes part of a tree of relational expressions with another tree. * @@ -196,11 +196,12 @@ public SubstitutionVisitor(RelNode target_, RelNode query_, this.query = Holder.of(MutableRels.toMutable(query_)); this.target = MutableRels.toMutable(target_); this.relBuilder = relBuilderFactory.create(cluster, null); - final Set parents = Sets.newIdentityHashSet(); + final Set<@Nullable MutableRel> parents = Sets.newIdentityHashSet(); final List allNodes = new ArrayList<>(); final MutableRelVisitor visitor = new MutableRelVisitor() { @Override public void visit(@Nullable MutableRel node) { + requireNonNull(node, "node"); parents.add(node.getParent()); allNodes.add(node); super.visit(node); @@ -321,7 +322,7 @@ void register(MutableRel result, MutableRel query) { * Reorders some of the operands in this expression so structural comparison, * i.e., based on string representation, can be more precise. */ - private static @Nullable RexNode canonizeNode(RexBuilder rexBuilder, RexNode condition) { + private static RexNode canonizeNode(RexBuilder rexBuilder, RexNode condition) { switch (condition.getKind()) { case AND: case OR: { @@ -351,7 +352,11 @@ void register(MutableRel result, MutableRel query) { if (left.toString().compareTo(right.toString()) <= 0) { return call; } - return RexUtil.invert(rexBuilder, call); + final RexNode result = RexUtil.invert(rexBuilder, call); + if (result == null) { + throw new NullPointerException("RexUtil.invert returned null for " + call); + } + return result; } case SEARCH: { final RexNode e = RexUtil.expandSearch(rexBuilder, null, condition); @@ -800,7 +805,7 @@ private static void reverseSubstitute(RelBuilder relBuilder, Holder query, System.out.println( "Unify failed:" + "\nQuery:\n" - + queryParent.toString() + + queryParent + "\nTarget:\n" + target.toString() + "\n"); @@ -929,10 +934,10 @@ protected class UnifyRuleCall { public UnifyRuleCall(UnifyRule rule, MutableRel query, MutableRel target, ImmutableList slots) { - this.rule = Objects.requireNonNull(rule); - this.query = Objects.requireNonNull(query); - this.target = Objects.requireNonNull(target); - this.slots = Objects.requireNonNull(slots); + this.rule = requireNonNull(rule); + this.query = requireNonNull(query); + this.target = requireNonNull(target); + this.slots = requireNonNull(slots); } public UnifyResult result(MutableRel result) { @@ -1089,7 +1094,7 @@ private ScanToCalcUnifyRule() { final RexShuttle shuttle = getRexShuttle(targetProjs); final List compenProjs; try { - compenProjs = (List) shuttle.apply( + compenProjs = shuttle.apply( rexBuilder.identityProjects(query.rowType)); } catch (MatchFailed e) { return null; @@ -1217,7 +1222,7 @@ private JoinOnLeftCalcToJoinUnifyRule() { } // Try pulling up MutableCalc only when Join condition references mapping. final List identityProjects = - (List) rexBuilder.identityProjects(qInput1.rowType); + rexBuilder.identityProjects(qInput1.rowType); if (!referenceByMapping(query.condition, qInput0Projs, identityProjects)) { return null; } @@ -1303,7 +1308,7 @@ private JoinOnRightCalcToJoinUnifyRule() { } // Try pulling up MutableCalc only when Join condition references mapping. final List identityProjects = - (List) rexBuilder.identityProjects(qInput0.rowType); + rexBuilder.identityProjects(qInput0.rowType); if (!referenceByMapping(query.condition, identityProjects, qInput1Projs)) { return null; } @@ -1531,6 +1536,9 @@ private AggregateOnCalcToAggregateUnifyRule() { if (unifiedAggregate instanceof MutableCalc) { final MutableCalc newCompenCalc = mergeCalc(rexBuilder, compenCalc, (MutableCalc) unifiedAggregate); + if (newCompenCalc == null) { + return null; + } return tryMergeParentCalcAndGenResult(call, newCompenCalc); } else { return tryMergeParentCalcAndGenResult(call, compenCalc); @@ -1704,8 +1712,9 @@ && sameRelCollectionNoOrderConsidered(queryGrandInputs, targetInputs)) { final Pair> queryInputExplained = explainCalc(queryInputs.get(i)); // Matching fails when filtering conditions are not equal or projects are not equal. - if (!splitFilter(call.getSimplify(), queryInputExplained0.left, - queryInputExplained.left).isAlwaysTrue()) { + RexNode residue = splitFilter(call.getSimplify(), queryInputExplained0.left, + queryInputExplained.left); + if (residue == null || !residue.isAlwaysTrue()) { return null; } for (Pair pair : Pair.zip( @@ -1812,8 +1821,8 @@ private static RexShuttle getExpandShuttle(RexProgram rexProgram) { /** Check if condition cond0 implies cond1. */ private static boolean implies( RelOptCluster cluster, RexNode cond0, RexNode cond1, RelDataType rowType) { - RexExecutorImpl rexImpl = - (RexExecutorImpl) cluster.getPlanner().getExecutor(); + RexExecutor rexImpl = + Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR); RexImplicationChecker rexImplicationChecker = new RexImplicationChecker(cluster.getRexBuilder(), rexImpl, rowType); return rexImplicationChecker.implies(cond0, cond1); @@ -1892,7 +1901,7 @@ public static MutableAggregate permute(MutableAggregate aggregate, || (compenGroupSet != null && constantCondInputRefs.containsAll(compenGroupSet))) { int projOffset = 0; if (!query.groupSets.equals(target.groupSets)) { - projOffset = compenGroupSet.size(); + projOffset = requireNonNull(compenGroupSet, "compenGroupSet").size(); } // Same level of aggregation. Generate a project. final List projects = new ArrayList<>(); diff --git a/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java b/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java index 21cc3d96ed1d..413bf28591c1 100644 --- a/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java +++ b/core/src/main/java/org/apache/calcite/plan/VisitorDataContext.java @@ -45,21 +45,21 @@ public class VisitorDataContext implements DataContext { private static final CalciteLogger LOGGER = new CalciteLogger(LoggerFactory.getLogger(VisitorDataContext.class.getName())); - private final Object[] values; + private final @Nullable Object[] values; - public VisitorDataContext(Object[] values) { + public VisitorDataContext(@Nullable Object[] values) { this.values = values; } - @Override public @Nullable SchemaPlus getRootSchema() { + @Override public SchemaPlus getRootSchema() { throw new RuntimeException("Unsupported"); } - @Override public @Nullable JavaTypeFactory getTypeFactory() { + @Override public JavaTypeFactory getTypeFactory() { throw new RuntimeException("Unsupported"); } - @Override public @Nullable QueryProvider getQueryProvider() { + @Override public QueryProvider getQueryProvider() { throw new RuntimeException("Unsupported"); } @@ -70,18 +70,18 @@ public VisitorDataContext(Object[] values) { return null; } } - public static DataContext of(RelNode targetRel, LogicalFilter queryRel) { + public static @Nullable DataContext of(RelNode targetRel, LogicalFilter queryRel) { return of(targetRel.getRowType(), queryRel.getCondition()); } - public static DataContext of(RelDataType rowType, RexNode rex) { + public static @Nullable DataContext of(RelDataType rowType, RexNode rex) { final int size = rowType.getFieldList().size(); - final Object[] values = new Object[size]; final List operands = ((RexCall) rex).getOperands(); final RexNode firstOperand = operands.get(0); final RexNode secondOperand = operands.get(1); final Pair value = getValue(firstOperand, secondOperand); if (value != null) { + final @Nullable Object[] values = new Object[size]; int index = value.getKey(); values[index] = value.getValue(); return new VisitorDataContext(values); @@ -90,11 +90,11 @@ public static DataContext of(RelDataType rowType, RexNode rex) { } } - public static DataContext of(RelDataType rowType, - List> usageList) { + public static @Nullable DataContext of(RelDataType rowType, + List> usageList) { final int size = rowType.getFieldList().size(); - final Object[] values = new Object[size]; - for (Pair elem : usageList) { + final @Nullable Object[] values = new Object[size]; + for (Pair elem : usageList) { Pair value = getValue(elem.getKey(), elem.getValue()); if (value == null) { LOGGER.warn("{} is not handled for {} for checking implication", @@ -149,12 +149,13 @@ public static DataContext of(RelDataType rowType, return Pair.of(index, rexLiteral.getValueAs(String.class)); default: // TODO: Support few more supported cases + Comparable value = rexLiteral.getValue(); LOGGER.warn("{} for value of class {} is being handled in default way", - type.getSqlTypeName(), rexLiteral.getValue().getClass()); - if (rexLiteral.getValue() instanceof NlsString) { - return Pair.of(index, ((NlsString) rexLiteral.getValue()).getValue()); + type.getSqlTypeName(), value == null ? null : value.getClass()); + if (value instanceof NlsString) { + return Pair.of(index, ((NlsString) value).getValue()); } else { - return Pair.of(index, rexLiteral.getValue()); + return Pair.of(index, value); } } } 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 374fc248c3ae..c0af0fdafd3b 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 @@ -68,6 +68,10 @@ import java.util.Queue; import java.util.Set; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + +import static java.util.Objects.requireNonNull; + /** * HepPlanner is a heuristic implementation of the {@link RelOptPlanner} * interface. @@ -178,7 +182,7 @@ public HepPlanner( @Override public RelNode changeTraits(RelNode rel, RelTraitSet toTraits) { // Ignore traits, except for the root, where we remember // what the final conversion should be. - if ((rel == root) || (rel == root.getCurrentRel())) { + if ((rel == root) || (rel == requireNonNull(root, "root").getCurrentRel())) { requestedRootTraits = toTraits; } return rel; @@ -193,7 +197,7 @@ public HepPlanner( // Get rid of everything except what's in the final plan. collectGarbage(); dumpRuleAttemptsInfo(); - return buildFinalPlan(root); + return buildFinalPlan(requireNonNull(root, "root")); } private void executeProgram(HepProgram program) { @@ -256,16 +260,17 @@ 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<>(); + Set ruleSet = instruction.ruleSet; + if (ruleSet == null) { + instruction.ruleSet = ruleSet = new LinkedHashSet<>(); + Class ruleClass = requireNonNull(instruction.ruleClass, "instruction.ruleClass"); for (RelOptRule rule : mapDescToRule.values()) { - if (instruction.ruleClass.isInstance(rule)) { - instruction.ruleSet.add(rule); + if (ruleClass.isInstance(rule)) { + ruleSet.add(rule); } } } - applyRules(instruction.ruleSet, true); + applyRules(ruleSet, true); } void executeInstruction( @@ -318,16 +323,17 @@ 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<>(); + Set ruleSet = instruction.ruleSet; + if (ruleSet == null) { + instruction.ruleSet = ruleSet = new LinkedHashSet<>(); for (RelOptRule rule : mapDescToRule.values()) { if (!(rule instanceof CommonRelSubExprRule)) { continue; } - instruction.ruleSet.add(rule); + ruleSet.add(rule); } } - applyRules(instruction.ruleSet, true); + applyRules(ruleSet, true); } void executeInstruction( @@ -335,7 +341,7 @@ void executeInstruction( LOGGER.trace("Entering subprogram"); for (;;) { int nTransformationsBefore = nTransformations; - executeProgram(instruction.subprogram); + executeProgram(requireNonNull(instruction.subprogram, "instruction.subprogram")); if (nTransformations == nTransformationsBefore) { // Nothing happened this time around. break; @@ -346,6 +352,7 @@ void executeInstruction( void executeInstruction( HepInstruction.BeginGroup instruction) { + assert currentProgram != null : "currentProgram must not be null"; assert currentProgram.group == null; currentProgram.group = instruction.endGroup; LOGGER.trace("Entering group"); @@ -357,7 +364,7 @@ void executeInstruction( assert currentProgram.group == instruction; currentProgram.group = null; instruction.collecting = false; - applyRules(instruction.ruleSet, true); + applyRules(requireNonNull(instruction.ruleSet, "instruction.ruleSet"), true); LOGGER.trace("Leaving group"); } @@ -395,12 +402,15 @@ private void applyRules( assert currentProgram != null : "currentProgram must not be null"; if (currentProgram.group != null) { assert currentProgram.group.collecting; - currentProgram.group.ruleSet.addAll(rules); + Set ruleSet = requireNonNull(currentProgram.group.ruleSet, + "currentProgram.group.ruleSet"); + ruleSet.addAll(rules); return; } LOGGER.trace("Applying rule set {}", rules); + requireNonNull(currentProgram, "currentProgram"); boolean fullRestartAfterTransformation = currentProgram.matchOrder != HepMatchOrder.ARBITRARY && currentProgram.matchOrder != HepMatchOrder.DEPTH_FIRST; @@ -409,7 +419,7 @@ private void applyRules( boolean fixedPoint; do { - Iterator iter = getGraphIterator(root); + Iterator iter = getGraphIterator(requireNonNull(root, "root")); fixedPoint = true; while (iter.hasNext()) { HepRelVertex vertex = iter.next(); @@ -420,20 +430,21 @@ private void applyRules( continue; } ++nMatches; - if (nMatches >= currentProgram.matchLimit) { + if (nMatches >= requireNonNull(currentProgram, "currentProgram").matchLimit) { return; } if (fullRestartAfterTransformation) { - iter = getGraphIterator(root); + iter = getGraphIterator(requireNonNull(root, "root")); } else { // To the extent possible, pick up where we left // off; have to create a new iterator because old // one was invalidated by transformation. iter = getGraphIterator(newVertex); - if (currentProgram.matchOrder == HepMatchOrder.DEPTH_FIRST) { + if (requireNonNull(currentProgram, "currentProgram").matchOrder + == HepMatchOrder.DEPTH_FIRST) { nMatches = depthFirstApply(iter, rules, forceConversions, nMatches); - if (nMatches >= currentProgram.matchLimit) { + if (nMatches >= requireNonNull(currentProgram, "currentProgram").matchLimit) { return; } } @@ -459,7 +470,7 @@ private Iterator getGraphIterator(HepRelVertex start) { collectGarbage(); assert currentProgram != null : "currentProgram must not be null"; - switch (currentProgram.matchOrder) { + switch (requireNonNull(currentProgram.matchOrder, "currentProgram.matchOrder")) { case ARBITRARY: case DEPTH_FIRST: return DepthFirstIterator.of(graph, start).iterator(); @@ -706,7 +717,7 @@ private HepRelVertex applyTransformationResults( if (thisCost == null) { continue; } - if (bestRel == null || thisCost.isLt(bestCost)) { + if (bestRel == null || thisCost.isLt(castNonNull(bestCost))) { bestRel = rel; bestCost = thisCost; } @@ -716,7 +727,7 @@ private HepRelVertex applyTransformationResults( ++nTransformations; notifyTransformation( call, - bestRel, + requireNonNull(bestRel, "bestRel"), true); // Before we add the result, make a copy of the list of vertex's @@ -972,6 +983,7 @@ private void collectGarbage() { // Yer basic mark-and-sweep. final Set rootSet = new HashSet<>(); + HepRelVertex root = requireNonNull(this.root, "this.root"); if (graph.vertexSet().contains(root)) { BreadthFirstIterator.reachable(rootSet, graph, root); } @@ -1023,6 +1035,11 @@ private void dumpGraph() { assertNoCycles(); + HepRelVertex root = this.root; + if (root == null) { + LOGGER.trace("dumpGraph: root is null"); + return; + } final RelMetadataQuery mq = root.getCluster().getMetadataQuery(); final StringBuilder sb = new StringBuilder(); sb.append("\nBreadth-first from root: {\n"); diff --git a/core/src/main/java/org/apache/calcite/plan/hep/HepRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/plan/hep/HepRelMetadataProvider.java index 9b42f2304a98..825b4204ce57 100644 --- a/core/src/main/java/org/apache/calcite/plan/hep/HepRelMetadataProvider.java +++ b/core/src/main/java/org/apache/calcite/plan/hep/HepRelMetadataProvider.java @@ -30,6 +30,8 @@ import java.lang.reflect.Method; +import static java.util.Objects.requireNonNull; + /** * HepRelMetadataProvider implements the {@link RelMetadataProvider} interface * by combining metadata from the rels inside of a {@link HepRelVertex}. @@ -45,7 +47,7 @@ class HepRelMetadataProvider implements RelMetadataProvider { return 107; } - @Override public @Nullable UnboundMetadata apply( + @Override public <@Nullable M extends @Nullable Metadata> UnboundMetadata apply( Class relClass, final Class metadataClass) { return (rel, mq) -> { @@ -55,9 +57,12 @@ class HepRelMetadataProvider implements RelMetadataProvider { HepRelVertex vertex = (HepRelVertex) rel; final RelNode rel2 = vertex.getCurrentRel(); UnboundMetadata function = - rel.getCluster().getMetadataProvider().apply(rel2.getClass(), - metadataClass); - return function.bind(rel2, mq); + requireNonNull(rel.getCluster().getMetadataProvider(), "metadataProvider") + .apply(rel2.getClass(), metadataClass); + return requireNonNull( + function, + () -> "no metadata provider for class " + metadataClass) + .bind(rel2, mq); }; } 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 d86b023d282a..0e25bce5b8e8 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 @@ -39,6 +39,8 @@ import java.util.Map; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** * Utility class to dump state of VolcanoPlanner. */ @@ -258,7 +260,11 @@ static void dumpGraphviz(VolcanoPlanner planner, PrintWriter pw) { } for (RelSubset subset : subsetPoset) { - for (RelSubset parent : subsetPoset.getChildren(subset)) { + List children = subsetPoset.getChildren(subset); + if (children == null) { + continue; + } + for (RelSubset parent : children) { pw.print("\t\tsubset"); pw.print(subset.getId()); pw.print(" -> subset"); @@ -272,7 +278,7 @@ static void dumpGraphviz(VolcanoPlanner planner, PrintWriter pw) { // Note: it is important that all the links are declared AFTER declaration of the nodes // Otherwise Graphviz creates nodes implicitly, and puts them into a wrong cluster pw.print("\troot -> subset"); - pw.print(planner.root.getId()); + pw.print(requireNonNull(planner.root, "planner.root").getId()); pw.println(";"); for (RelSet set : ordering.immutableSortedCopy(planner.allSets)) { for (RelNode rel : set.rels) { diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/IterativeRuleDriver.java b/core/src/main/java/org/apache/calcite/plan/volcano/IterativeRuleDriver.java index 3883e48e2804..ed6a379ffbfc 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/IterativeRuleDriver.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/IterativeRuleDriver.java @@ -21,6 +21,8 @@ import org.slf4j.Logger; +import static java.util.Objects.requireNonNull; + /*** *

The algorithm executes repeatedly. The exact rules * that may be fired varies. @@ -46,7 +48,8 @@ class IterativeRuleDriver implements RuleDriver { @Override public void drive() { while (true) { - LOGGER.debug("PLANNER = {}; COST = {}", this, planner.root.bestCost); + LOGGER.debug("PLANNER = {}; COST = {}", this, + requireNonNull(planner.root, "planner.root").bestCost); VolcanoRuleMatch match = ruleQueue.popMatch(); if (match == null) { 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 13eae4d6ec84..2330d7389671 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 @@ -90,7 +90,10 @@ class TopDownRuleDriver implements RuleDriver { TaskDescriptor description = new TaskDescriptor(); // Starting from the root's OptimizeGroup task. - tasks.push(new OptimizeGroup(planner.root, planner.infCost)); + tasks.push( + new OptimizeGroup( + requireNonNull(planner.root, "planner.root"), + planner.infCost)); // ensure materialized view roots get explored. // Note that implementation rules or enforcement rules are not applied @@ -112,7 +115,8 @@ class TopDownRuleDriver implements RuleDriver { private void exploreMaterializationRoots() { for (RelSubset extraRoot : planner.explorationRoots) { RelSet rootSet = VolcanoPlanner.equivRoot(extraRoot.set); - if (rootSet == planner.root.set) { + RelSubset root = requireNonNull(planner.root, "planner.root"); + if (rootSet == root.set) { continue; } for (RelNode rel : extraRoot.set.rels) { @@ -188,7 +192,7 @@ private void clearProcessed(RelSet set) { } // extra callback from each task - if (!applying.onProduce(node)) { + if (!requireNonNull(applying, "applying").onProduce(node)) { return; } @@ -237,6 +241,7 @@ private void clearProcessed(RelSet set) { } else { boolean optimizing = subset.set.subsets.stream() .anyMatch(s -> s.taskState == RelSubset.OptimizeState.OPTIMIZING); + GeneratorTask applying = requireNonNull(this.applying, "this.applying"); tasks.push( new OptimizeMExpr(node, applying.group(), applying.exploring() && !optimizing)); @@ -588,7 +593,9 @@ private class ApplyRule implements GeneratorTask { VolcanoRuleMatch match = ruleQueue.popMatch( Pair.of(rel, m -> m.getRule() instanceof ConverterRule - && m.getRule().getOutTrait().satisfies(group.getTraitSet().getConvention()))); + && ((ConverterRule) m.getRule()).getOutTrait().satisfies( + requireNonNull(group.getTraitSet().getConvention(), + () -> "convention for " + group)))); if (match != null) { tasks.add(new ApplyRule(match, group, false)); } @@ -672,8 +679,8 @@ private class OptimizeInputs implements Task { .item("processingChild", processingChild); } - private List lowerBounds; - private RelOptCost lowerBoundSum; + private @Nullable List lowerBounds; + private @Nullable RelOptCost lowerBoundSum; @Override public void perform() { RelOptCost bestCost = group.bestCost; if (!bestCost.isInfinite()) { @@ -687,14 +694,14 @@ private class OptimizeInputs implements Task { if (upperForInput.isInfinite()) { upperForInput = planner.upperBoundForInputs(mExpr, upperBound); } - lowerBounds = new ArrayList<>(childCount); + List lowerBounds = this.lowerBounds = new ArrayList<>(childCount); for (RelNode input : mExpr.getInputs()) { RelOptCost lb = planner.getLowerBound(input); lowerBounds.add(lb); lowerBoundSum = lowerBoundSum == null ? lb : lowerBoundSum.plus(lb); } } - if (upperForInput.isLt(lowerBoundSum)) { + if (upperForInput.isLt(requireNonNull(lowerBoundSum, "lowerBoundSum"))) { LOGGER.debug( "Skip O_INPUT because of lower bound. LB = {}, UP = {}", lowerBoundSum, upperForInput); @@ -727,8 +734,8 @@ private class OptimizeInputs implements Task { // UB(one input) // = UB(current subset) - Parent's NonCumulativeCost - LB(other inputs) // = UB(current subset) - Parent's NonCumulativeCost - LB(all inputs) + LB(current input) - upper = upperForInput.minus(lowerBoundSum) - .plus(lowerBounds.get(processingChild)); + upper = upperForInput.minus(requireNonNull(lowerBoundSum, "lowerBoundSum")) + .plus(requireNonNull(lowerBounds, "lowerBounds").get(processingChild)); } if (input.taskState != null && upper.isLe(input.upperBound)) { LOGGER.debug("Failed to optimize because of upper bound. LB = {}, UP = {}", @@ -795,11 +802,13 @@ private class CheckInput implements Task { } // Update the context. - if (context.lowerBoundSum != null && context.lowerBoundSum != planner.infCost) { - context.lowerBoundSum = context. - lowerBoundSum.minus(context.lowerBounds.get(i)); - context.lowerBoundSum = context.lowerBoundSum.plus(winner); - context.lowerBounds.set(i, winner); + RelOptCost lowerBoundSum = context.lowerBoundSum; + if (lowerBoundSum != null && lowerBoundSum != planner.infCost) { + List lowerBounds = requireNonNull(context.lowerBounds, "context.lowerBounds"); + lowerBoundSum = lowerBoundSum.minus(lowerBounds.get(i)); + lowerBoundSum = lowerBoundSum.plus(winner); + context.lowerBoundSum = lowerBoundSum; + lowerBounds.set(i, winner); } } } diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRelMetadataProvider.java index 7eb261fdeb90..3a6ae005035a 100644 --- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRelMetadataProvider.java +++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoRelMetadataProvider.java @@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import java.lang.reflect.Method; +import java.util.Objects; /** * VolcanoRelMetadataProvider implements the {@link RelMetadataProvider} @@ -45,7 +46,7 @@ public class VolcanoRelMetadataProvider implements RelMetadataProvider { return 103; } - @Override public @Nullable UnboundMetadata apply( + @Override public <@Nullable M extends @Nullable Metadata> @Nullable UnboundMetadata apply( Class relClass, final Class metadataClass) { if (relClass != RelSubset.class) { @@ -55,8 +56,9 @@ public class VolcanoRelMetadataProvider implements RelMetadataProvider { return (rel, mq) -> { final RelSubset subset = (RelSubset) rel; - final RelMetadataProvider provider = - rel.getCluster().getMetadataProvider(); + final RelMetadataProvider provider = Objects.requireNonNull( + rel.getCluster().getMetadataProvider(), + "metadataProvider"); // REVIEW jvs 29-Mar-2006: I'm not sure what the correct precedence // should be here. Letting the current best plan take the first shot is @@ -67,10 +69,11 @@ public class VolcanoRelMetadataProvider implements RelMetadataProvider { // First, try current best implementation. If it knows how to answer // this query, treat it as the most reliable. if (subset.best != null) { + RelNode best = subset.best; final UnboundMetadata function = - provider.apply(subset.best.getClass(), metadataClass); + provider.apply(best.getClass(), metadataClass); if (function != null) { - final M metadata = function.bind(subset.best, mq); + final M metadata = function.bind(best, mq); if (metadata != null) { return metadata; } diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java index 515da9a2daa1..1c90915a0033 100644 --- a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java +++ b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java @@ -446,7 +446,7 @@ private static RelDataType toSql(RelDataTypeFactory typeFactory, return nameMatcher; } - @Override public @Nullable C unwrap(Class aClass) { + @Override public @Nullable C unwrap(Class aClass) { if (aClass.isInstance(this)) { return aClass.cast(this); } diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java b/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java index ffd6b9f8ca07..220e39883142 100644 --- a/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java +++ b/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java @@ -58,6 +58,8 @@ import java.util.ArrayList; import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Context for populating a {@link Prepare.Materialization}. */ @@ -99,8 +101,10 @@ void populate(Materialization materialization) { // take the best (whatever that means), or all of them? useStar(schema, materialization); - RelOptTable table = - this.catalogReader.getTable(materialization.materializedTable.path()); + List tableName = materialization.materializedTable.path(); + RelOptTable table = requireNonNull( + this.catalogReader.getTable(tableName), + () -> "table " + tableName + " is not found"); materialization.tableRel = sqlToRelConverter2.toRel(table, ImmutableList.of()); } @@ -108,14 +112,15 @@ void populate(Materialization materialization) { * {@link StarTable} defined in {@code schema}. * Uses the first star table that fits. */ private void useStar(CalciteSchema schema, Materialization materialization) { - for (Callback x : useStar(schema, materialization.queryRel)) { + RelNode queryRel = requireNonNull(materialization.queryRel, "materialization.queryRel"); + for (Callback x : useStar(schema, queryRel)) { // Success -- we found a star table that matches. materialization.materialize(x.rel, x.starRelOptTable); if (CalciteSystemProperty.DEBUG.value()) { System.out.println("Materialization " + materialization.materializedTable + " matched star table " + x.starTable + "; query after re-write: " - + RelOptUtil.toString(materialization.queryRel)); + + RelOptUtil.toString(queryRel)); } } } 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 fd474e650d12..837a4cb8315c 100644 --- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java +++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java @@ -47,6 +47,7 @@ import org.apache.calcite.linq4j.tree.MethodCallExpression; import org.apache.calcite.linq4j.tree.NewExpression; import org.apache.calcite.linq4j.tree.ParameterExpression; +import org.apache.calcite.linq4j.tree.PseudoField; import org.apache.calcite.materialize.MaterializationService; import org.apache.calcite.plan.Contexts; import org.apache.calcite.plan.Convention; @@ -77,6 +78,7 @@ import org.apache.calcite.runtime.Bindable; import org.apache.calcite.runtime.Hook; import org.apache.calcite.runtime.Typed; +import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.schema.Schemas; import org.apache.calcite.schema.Table; import org.apache.calcite.server.CalciteServerStatement; @@ -529,7 +531,7 @@ private CalciteSignature simplePrepare(Context context, String sql) { @SuppressWarnings("unchecked") final List list = (List) ImmutableList.of(1); final List origin = null; - final List> origins = + final List<@Nullable List> origins = Collections.nCopies(x.getFieldCount(), origin); final List columns = getColumnMetaDataList(typeFactory, x, x, origins); @@ -684,7 +686,7 @@ CalciteSignature prepare2_( } RelDataType jdbcType = makeStruct(typeFactory, x); - final List> originList = preparedResult.getFieldOrigins(); + final List> originList = preparedResult.getFieldOrigins(); final List columns = getColumnMetaDataList(typeFactory, x, jdbcType, originList); Class resultClazz = null; @@ -735,7 +737,7 @@ private SqlValidator createSqlValidator(Context context, private List getColumnMetaDataList( JavaTypeFactory typeFactory, RelDataType x, RelDataType jdbcType, - List> originList) { + List> originList) { final List columns = new ArrayList<>(); for (Ord pair : Ord.zip(jdbcType.getFieldList())) { final RelDataTypeField field = pair.e; @@ -912,9 +914,10 @@ public R perform(CalciteServerStatement statement, final CalcitePrepare.Context prepareContext = statement.createPrepareContext(); final JavaTypeFactory typeFactory = prepareContext.getTypeFactory(); + SchemaPlus defaultSchema = config.getDefaultSchema(); final CalciteSchema schema = - config.getDefaultSchema() != null - ? CalciteSchema.from(config.getDefaultSchema()) + defaultSchema != null + ? CalciteSchema.from(defaultSchema) : prepareContext.getRootSchema(); CalciteCatalogReader catalogReader = new CalciteCatalogReader(schema.root(), @@ -1254,10 +1257,15 @@ private static List simpleList(BlockStatement statement) { switch (expression.getNodeType()) { case MemberAccess: // Case-sensitive name match because name was previously resolved. + MemberExpression memberExpression = (MemberExpression) expression; + PseudoField field = memberExpression.field; + Expression targetExpression = Objects.requireNonNull(memberExpression.expression, + () -> "static field access is not implemented yet." + + " field.name=" + field.getName() + + ", field.declaringClass=" + field.getDeclaringClass()); return rexBuilder.makeFieldAccess( - toRex( - ((MemberExpression) expression).expression), - ((MemberExpression) expression).field.getName(), + toRex(targetExpression), + field.getName(), true); case GreaterThan: return binary(expression, SqlStdOperatorTable.GREATER_THAN); diff --git a/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java b/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java index 6bdb9be2bd98..f7d02f3e2c76 100644 --- a/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java +++ b/core/src/main/java/org/apache/calcite/prepare/LixToRelTranslator.java @@ -18,12 +18,14 @@ import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.linq4j.Queryable; +import org.apache.calcite.linq4j.tree.BlockStatement; import org.apache.calcite.linq4j.tree.Blocks; import org.apache.calcite.linq4j.tree.ConstantExpression; import org.apache.calcite.linq4j.tree.Expression; import org.apache.calcite.linq4j.tree.FunctionExpression; import org.apache.calcite.linq4j.tree.MethodCallExpression; import org.apache.calcite.linq4j.tree.NewExpression; +import org.apache.calcite.linq4j.tree.ParameterExpression; import org.apache.calcite.linq4j.tree.Types; import org.apache.calcite.plan.RelOptCluster; import org.apache.calcite.plan.RelOptTable; @@ -38,10 +40,13 @@ import com.google.common.collect.ImmutableList; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Translates a tree of linq4j {@link Queryable} nodes to a tree of * {@link RelNode} planner nodes. @@ -59,6 +64,19 @@ class LixToRelTranslator { this.typeFactory = (JavaTypeFactory) cluster.getTypeFactory(); } + private static BlockStatement getBody(FunctionExpression expression) { + return requireNonNull(expression.body, () -> "body in " + expression); + } + + private static List getParameterList(FunctionExpression expression) { + return requireNonNull(expression.parameterList, () -> "parameterList in " + expression); + } + + private static Expression getTargetExpression(MethodCallExpression call) { + return requireNonNull(call.targetExpression, + "translation of static calls is not supported yet"); + } + RelOptTable.ToRelContext toRelContext() { if (preparingStmt instanceof RelOptTable.ViewExpander) { final RelOptTable.ViewExpander viewExpander = @@ -86,14 +104,14 @@ public RelNode translate(Expression expression) { RelNode input; switch (method) { case SELECT: - input = translate(call.targetExpression); + input = translate(getTargetExpression(call)); return LogicalProject.create(input, ImmutableList.of(), toRex(input, (FunctionExpression) call.expressions.get(0)), (List) null); case WHERE: - input = translate(call.targetExpression); + input = translate(getTargetExpression(call)); return LogicalFilter.create(input, toRex((FunctionExpression) call.expressions.get(0), input)); @@ -102,18 +120,20 @@ public RelNode translate(Expression expression) { RelOptTableImpl.create(null, typeFactory.createJavaType( Types.toClass( - Types.getElementType(call.targetExpression.getType()))), + getElementType(call))), ImmutableList.of(), - call.targetExpression), + getTargetExpression(call)), ImmutableList.of()); case SCHEMA_GET_TABLE: return LogicalTableScan.create(cluster, RelOptTableImpl.create(null, typeFactory.createJavaType((Class) - ((ConstantExpression) call.expressions.get(1)).value), + requireNonNull( + ((ConstantExpression) call.expressions.get(1)).value, + "argument 1 (0-based) is null Class")), ImmutableList.of(), - call.targetExpression), + getTargetExpression(call)), ImmutableList.of()); default: @@ -125,6 +145,13 @@ public RelNode translate(Expression expression) { "unknown expression type " + expression.getNodeType()); } + private static Type getElementType(MethodCallExpression call) { + Type type = getTargetExpression(call).getType(); + return requireNonNull( + Types.getElementType(type), + () -> "unable to figure out element type from " + type); + } + private List toRex( RelNode child, FunctionExpression expression) { RexBuilder rexBuilder = cluster.getRexBuilder(); @@ -134,9 +161,9 @@ private List toRex( CalcitePrepareImpl.ScalarTranslator translator = CalcitePrepareImpl.EmptyScalarTranslator .empty(rexBuilder) - .bind(expression.parameterList, list); + .bind(getParameterList(expression), list); final List rexList = new ArrayList<>(); - final Expression simple = Blocks.simple(expression.body); + final Expression simple = Blocks.simple(getBody(expression)); for (Expression expression1 : fieldExpressions(simple)) { rexList.add(translator.toRex(expression1)); } @@ -162,8 +189,8 @@ List toRexList( list.add(rexBuilder.makeRangeReference(input)); } return CalcitePrepareImpl.EmptyScalarTranslator.empty(rexBuilder) - .bind(expression.parameterList, list) - .toRexList(expression.body); + .bind(getParameterList(expression), list) + .toRexList(getBody(expression)); } RexNode toRex( @@ -175,7 +202,7 @@ RexNode toRex( list.add(rexBuilder.makeRangeReference(input)); } return CalcitePrepareImpl.EmptyScalarTranslator.empty(rexBuilder) - .bind(expression.parameterList, list) - .toRex(expression.body); + .bind(getParameterList(expression), list) + .toRex(getBody(expression)); } } diff --git a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java index cca1adf21457..81e796fa7f87 100644 --- a/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java +++ b/core/src/main/java/org/apache/calcite/prepare/PlannerImpl.java @@ -67,7 +67,8 @@ import java.io.Reader; import java.util.List; -import java.util.Objects; + +import static java.util.Objects.requireNonNull; /** Implementation of {@link org.apache.calcite.tools.Planner}. */ public class PlannerImpl implements Planner, ViewExpander { @@ -101,11 +102,9 @@ public class PlannerImpl implements Planner, ViewExpander { private @Nullable SqlValidator validator; private @Nullable SqlNode validatedSqlNode; - // set in STATE_5_CONVERT - private @Nullable RelRoot root; - /** Creates a planner. Not a public API; call * {@link org.apache.calcite.tools.Frameworks#getPlanner} instead. */ + @SuppressWarnings("method.invocation.invalid") public PlannerImpl(FrameworkConfig config) { this.costFactory = config.getCostFactory(); this.defaultSchema = config.getDefaultSchema(); @@ -119,12 +118,13 @@ public PlannerImpl(FrameworkConfig config) { this.convertletTable = config.getConvertletTable(); this.executor = config.getExecutor(); this.context = config.getContext(); - this.connectionConfig = connConfig(); + this.connectionConfig = connConfig(context, parserConfig); reset(); } /** Gets a user-defined config and appends default connection values. */ - private CalciteConnectionConfig connConfig() { + private static CalciteConnectionConfig connConfig(Context context, + SqlParser.Config parserConfig) { CalciteConnectionConfigImpl config = Util.first( context.unwrap(CalciteConnectionConfigImpl.class), CalciteConnectionConfig.DEFAULT); @@ -152,7 +152,7 @@ private void ensure(State state) { } @Override public RelTraitSet getEmptyTraitSet() { - return Objects.requireNonNull(planner, "planner").emptyTraitSet(); + return requireNonNull(planner, "planner").emptyTraitSet(); } @Override public void close() { @@ -181,7 +181,7 @@ private void ready() { connectionConfig.typeSystem(RelDataTypeSystem.class, RelDataTypeSystem.DEFAULT); typeFactory = new JavaTypeFactoryImpl(typeSystem); - planner = new VolcanoPlanner(costFactory, context); + RelOptPlanner planner = this.planner = new VolcanoPlanner(costFactory, context); RelOptUtil.registerDefaultRules(planner, connectionConfig.materializationsEnabled(), Hook.ENABLE_BINDABLE.get(false)); @@ -247,17 +247,18 @@ private void ready() { @Override public RelRoot rel(SqlNode sql) { ensure(State.STATE_4_VALIDATED); - assert validatedSqlNode != null; + SqlNode validatedSqlNode = requireNonNull(this.validatedSqlNode, + "validatedSqlNode is null. Need to call #validate() first"); final RexBuilder rexBuilder = createRexBuilder(); final RelOptCluster cluster = RelOptCluster.create( - Objects.requireNonNull(planner, "planner"), + requireNonNull(planner, "planner"), rexBuilder); final SqlToRelConverter.Config config = sqlToRelConverterConfig.withTrimUnusedFields(false); final SqlToRelConverter sqlToRelConverter = new SqlToRelConverter(this, validator, createCatalogReader(), cluster, convertletTable, config); - root = + RelRoot root = sqlToRelConverter.convertQuery(validatedSqlNode, false, true); root = root.withRel(sqlToRelConverter.flattenTypes(root.rel, true)); final RelBuilder relBuilder = @@ -285,8 +286,10 @@ public class ViewExpanderImpl implements ViewExpander { @Override public RelRoot expandView(RelDataType rowType, String queryString, List schemaPath, @Nullable List viewPath) { + RelOptPlanner planner = this.planner; if (planner == null) { ready(); + planner = requireNonNull(this.planner, "planner"); } SqlParser parser = SqlParser.create(queryString, parserConfig); SqlNode sqlNode; @@ -320,8 +323,8 @@ public class ViewExpanderImpl implements ViewExpander { // CalciteCatalogReader is stateless; no need to store one private CalciteCatalogReader createCatalogReader() { - final SchemaPlus rootSchema = rootSchema( - Objects.requireNonNull(defaultSchema, "defaultSchema")); + SchemaPlus defaultSchema = requireNonNull(this.defaultSchema, "defaultSchema"); + final SchemaPlus rootSchema = rootSchema(defaultSchema); return new CalciteCatalogReader( CalciteSchema.from(rootSchema), @@ -344,10 +347,11 @@ private SqlValidator createSqlValidator(CalciteCatalogReader catalogReader) { private static SchemaPlus rootSchema(SchemaPlus schema) { for (;;) { - if (schema.getParentSchema() == null) { + SchemaPlus parentSchema = schema.getParentSchema(); + if (parentSchema == null) { return schema; } - schema = schema.getParentSchema(); + schema = parentSchema; } } @@ -357,7 +361,7 @@ private RexBuilder createRexBuilder() { } @Override public JavaTypeFactory getTypeFactory() { - return Objects.requireNonNull(typeFactory, "typeFactory"); + return requireNonNull(typeFactory, "typeFactory"); } @Override public RelNode transform(int ruleSetIndex, RelTraitSet requiredOutputTraits, @@ -365,10 +369,11 @@ private RexBuilder createRexBuilder() { ensure(State.STATE_5_CONVERTED); rel.getCluster().setMetadataProvider( new CachingRelMetadataProvider( - rel.getCluster().getMetadataProvider(), + requireNonNull(rel.getCluster().getMetadataProvider(), "metadataProvider"), rel.getCluster().getPlanner())); Program program = programs.get(ruleSetIndex); - return program.run(planner, rel, requiredOutputTraits, ImmutableList.of(), + return program.run(requireNonNull(planner, "planner"), + rel, requiredOutputTraits, ImmutableList.of(), ImmutableList.of()); } 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 6d14e8e173f7..858b66ab13a0 100644 --- a/core/src/main/java/org/apache/calcite/prepare/Prepare.java +++ b/core/src/main/java/org/apache/calcite/prepare/Prepare.java @@ -76,10 +76,11 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Objects; import static org.apache.calcite.linq4j.Nullness.castNonNull; +import static java.util.Objects.requireNonNull; + /** * Abstract base for classes that implement * the process of preparing and executing SQL expressions. @@ -450,7 +451,9 @@ public abstract static class AbstractPreparingTable (ModifiableViewTable) table; final ModifiableViewTable extendedView = modifiableViewTable.extend(dedupedExtendedFields, - getRelOptSchema().getTypeFactory()); + requireNonNull( + getRelOptSchema(), + () -> "relOptSchema for table " + getQualifiedName()).getTypeFactory()); return extend(extendedView); } throw new RuntimeException("Cannot extend " + table); @@ -510,7 +513,7 @@ protected PreparedExplain( return null; } - @Override public List> getFieldOrigins() { + @Override public List<@Nullable List> getFieldOrigins() { return Collections.singletonList( Collections.nCopies(4, null)); } @@ -542,7 +545,7 @@ public interface PreparedResult { * Returns a list describing, for each result field, the origin of the * field as a 4-element list of (database, schema, table, column). */ - List> getFieldOrigins(); + List> getFieldOrigins(); /** * Returns a record type whose fields are the parameters of this statement. @@ -568,22 +571,22 @@ public abstract static class PreparedResultImpl protected final RelDataType rowType; protected final boolean isDml; protected final TableModify.@Nullable Operation tableModOp; - protected final List> fieldOrigins; + protected final List> fieldOrigins; protected final List collations; protected PreparedResultImpl( RelDataType rowType, RelDataType parameterRowType, - List> fieldOrigins, + List> fieldOrigins, List collations, RelNode rootRel, TableModify.@Nullable Operation tableModOp, boolean isDml) { - this.rowType = Objects.requireNonNull(rowType); - this.parameterRowType = Objects.requireNonNull(parameterRowType); - this.fieldOrigins = Objects.requireNonNull(fieldOrigins); + this.rowType = requireNonNull(rowType); + this.parameterRowType = requireNonNull(parameterRowType); + this.fieldOrigins = requireNonNull(fieldOrigins); this.collations = ImmutableList.copyOf(collations); - this.rootRel = Objects.requireNonNull(rootRel); + this.rootRel = requireNonNull(rootRel); this.tableModOp = tableModOp; this.isDml = isDml; } @@ -596,7 +599,7 @@ protected PreparedResultImpl( return tableModOp; } - @Override public List> getFieldOrigins() { + @Override public List> getFieldOrigins() { return fieldOrigins; } diff --git a/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java b/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java index 88f94de304bc..261ae017de32 100644 --- a/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java +++ b/core/src/main/java/org/apache/calcite/prepare/QueryableRelBuilder.java @@ -59,6 +59,8 @@ import static org.apache.calcite.linq4j.Nullness.castNonNull; +import static java.util.Objects.requireNonNull; + /** * Implementation of {@link QueryableFactory} * that builds a tree of {@link RelNode} planner nodes. Used by @@ -83,7 +85,7 @@ */ class QueryableRelBuilder implements QueryableFactory { private final LixToRelTranslator translator; - private RelNode rel; + private @Nullable RelNode rel; QueryableRelBuilder(LixToRelTranslator translator) { this.translator = translator; @@ -93,7 +95,7 @@ RelNode toRel(Queryable queryable) { if (queryable instanceof QueryableDefaults.Replayable) { //noinspection unchecked ((QueryableDefaults.Replayable) queryable).replay(this); - return rel; + return requireNonNull(rel, "rel"); } if (queryable instanceof AbstractTableQueryable) { final AbstractTableQueryable tableQueryable = @@ -112,7 +114,10 @@ RelNode toRel(Queryable queryable) { return LogicalTableScan.create(translator.cluster, relOptTable, ImmutableList.of()); } } - return translator.translate(queryable.getExpression()); + return translator.translate( + requireNonNull( + queryable.getExpression(), + () -> "null expression from " + queryable)); } /** Sets the output of this event. */ @@ -132,7 +137,7 @@ private void setRel(RelNode rel) { @Override public T aggregate( Queryable source, - FunctionExpression> selector) { + FunctionExpression> selector) { throw new UnsupportedOperationException(); } 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 b45336599bcc..e9261f50321e 100644 --- a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java +++ b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java @@ -65,15 +65,16 @@ import java.util.AbstractList; import java.util.Collection; import java.util.List; -import java.util.Objects; import java.util.Set; import java.util.function.Function; +import static java.util.Objects.requireNonNull; + /** * Implementation of {@link org.apache.calcite.plan.RelOptTable}. */ public class RelOptTableImpl extends Prepare.AbstractPreparingTable { - private final RelOptSchema schema; + private final @Nullable RelOptSchema schema; private final RelDataType rowType; private final @Nullable Table table; private final @Nullable Function expressionFunction; @@ -89,14 +90,14 @@ public class RelOptTableImpl extends Prepare.AbstractPreparingTable { private final @Nullable Double rowCount; private RelOptTableImpl( - RelOptSchema schema, + @Nullable RelOptSchema schema, RelDataType rowType, List names, @Nullable Table table, @Nullable Function expressionFunction, @Nullable Double rowCount) { this.schema = schema; - this.rowType = Objects.requireNonNull(rowType); + this.rowType = requireNonNull(rowType); this.names = ImmutableList.copyOf(names); this.table = table; // may be null this.expressionFunction = expressionFunction; // may be null @@ -104,7 +105,7 @@ private RelOptTableImpl( } public static RelOptTableImpl create( - RelOptSchema schema, + @Nullable RelOptSchema schema, RelDataType rowType, List names, Expression expression) { @@ -113,7 +114,7 @@ public static RelOptTableImpl create( } public static RelOptTableImpl create( - RelOptSchema schema, + @Nullable RelOptSchema schema, RelDataType rowType, List names, Table table, @@ -122,7 +123,7 @@ public static RelOptTableImpl create( c -> expression, table.getStatistic().getRowCount()); } - public static RelOptTableImpl create(RelOptSchema schema, RelDataType rowType, + public static RelOptTableImpl create(@Nullable RelOptSchema schema, RelDataType rowType, Table table, Path path) { final SchemaPlus schemaPlus = MySchemaPlus.create(path); return new RelOptTableImpl(schema, rowType, Pair.left(path), table, @@ -130,7 +131,7 @@ public static RelOptTableImpl create(RelOptSchema schema, RelDataType rowType, table.getStatistic().getRowCount()); } - public static RelOptTableImpl create(RelOptSchema schema, RelDataType rowType, + public static RelOptTableImpl create(@Nullable RelOptSchema schema, RelDataType rowType, final CalciteSchema.TableEntry tableEntry, @Nullable Double rowCount) { final Table table = tableEntry.getTable(); return new RelOptTableImpl(schema, rowType, tableEntry.path(), @@ -180,7 +181,7 @@ private static Function getClassExpressionFunction( } } - public static RelOptTableImpl create(RelOptSchema schema, + public static RelOptTableImpl create(@Nullable RelOptSchema schema, RelDataType rowType, Table table, ImmutableList names) { assert table instanceof TranslatableTable || table instanceof ScannableTable @@ -188,7 +189,7 @@ public static RelOptTableImpl create(RelOptSchema schema, return new RelOptTableImpl(schema, rowType, names, table, null, null); } - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { if (clazz.isInstance(this)) { return clazz.cast(this); } @@ -201,7 +202,7 @@ public static RelOptTableImpl create(RelOptSchema schema, return t; } } - if (clazz == CalciteSchema.class) { + if (clazz == CalciteSchema.class && schema != null) { return clazz.cast( Schemas.subSchema(((CalciteCatalogReader) schema).rootSchema, Util.skipLast(getQualifiedName()))); @@ -217,9 +218,10 @@ public static RelOptTableImpl create(RelOptSchema schema, } @Override protected RelOptTable extend(Table extendedTable) { + RelOptSchema schema = requireNonNull(getRelOptSchema(), "relOptSchema"); final RelDataType extendedRowType = - extendedTable.getRowType(getRelOptSchema().getTypeFactory()); - return new RelOptTableImpl(getRelOptSchema(), extendedRowType, getQualifiedName(), + extendedTable.getRowType(schema.getTypeFactory()); + return new RelOptTableImpl(schema, extendedRowType, getQualifiedName(), extendedTable, expressionFunction, getRowCount()); } @@ -246,7 +248,7 @@ public static RelOptTableImpl create(RelOptSchema schema, return 100d; } - @Override public RelOptSchema getRelOptSchema() { + @Override public @Nullable RelOptSchema getRelOptSchema() { return schema; } @@ -273,7 +275,7 @@ public static RelOptTableImpl create(RelOptSchema schema, final RelOptTable relOptTable = new RelOptTableImpl(this.schema, b.build(), this.names, this.table, this.expressionFunction, this.rowCount) { - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { if (clazz.isAssignableFrom(InitializerExpressionFactory.class)) { return clazz.cast(NullInitializerExpressionFactory.INSTANCE); } @@ -289,14 +291,14 @@ public static RelOptTableImpl create(RelOptSchema schema, return LogicalTableScan.create(context.getCluster(), this, context.getTableHints()); } - @Override public List getCollationList() { + @Override public @Nullable List getCollationList() { if (table != null) { return table.getStatistic().getCollations(); } return ImmutableList.of(); } - @Override public RelDistribution getDistribution() { + @Override public @Nullable RelDistribution getDistribution() { if (table != null) { return table.getStatistic().getDistribution(); } @@ -310,11 +312,14 @@ public static RelOptTableImpl create(RelOptSchema schema, return false; } - @Override public List getKeys() { - return table.getStatistic().getKeys(); + @Override public @Nullable List getKeys() { + if (table != null) { + return table.getStatistic().getKeys(); + } + return ImmutableList.of(); } - @Override public List getReferentialConstraints() { + @Override public @Nullable List getReferentialConstraints() { if (table != null) { return table.getStatistic().getReferentialConstraints(); } @@ -343,9 +348,12 @@ public static RelOptTableImpl create(RelOptSchema schema, } @Override public SqlMonotonicity getMonotonicity(String columnName) { + if (table == null) { + return SqlMonotonicity.NOT_MONOTONIC; + } List collations = table.getStatistic().getCollations(); if (collations == null) { - return null; + return SqlMonotonicity.NOT_MONOTONIC; } for (RelCollation collation : collations) { final RelFieldCollation fieldCollation = @@ -407,7 +415,8 @@ public static RelDataType realRowType(RelOptTable table) { return rowType; } final RelDataTypeFactory.Builder builder = - table.getRelOptSchema().getTypeFactory().builder(); + requireNonNull(table.getRelOptSchema(), + () -> "relOptSchema for table " + table).getTypeFactory().builder(); for (RelDataTypeField field : rowType.getFieldList()) { if (strategies.get(field.getIndex()) != ColumnStrategy.VIRTUAL) { builder.add(field); @@ -481,7 +490,7 @@ public static MySchemaPlus create(Path path) { return schema.isMutable(); } - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { return null; } @@ -526,7 +535,7 @@ public static MySchemaPlus create(Path path) { return schema.getSubSchemaNames(); } - @Override public Expression getExpression(SchemaPlus parentSchema, + @Override public Expression getExpression(@Nullable SchemaPlus parentSchema, String name) { return schema.getExpression(parentSchema, name); } diff --git a/core/src/main/java/org/apache/calcite/profile/ProfilerImpl.java b/core/src/main/java/org/apache/calcite/profile/ProfilerImpl.java index 37296db83c12..1164bb3c49dc 100644 --- a/core/src/main/java/org/apache/calcite/profile/ProfilerImpl.java +++ b/core/src/main/java/org/apache/calcite/profile/ProfilerImpl.java @@ -477,7 +477,7 @@ static class Space { /** Returns the distribution created from this space, or null if no * distribution has been registered yet. */ - public Distribution distribution() { + public @Nullable Distribution distribution() { return run.distributions.get(columnOrdinals); } diff --git a/core/src/main/java/org/apache/calcite/rel/RelInput.java b/core/src/main/java/org/apache/calcite/rel/RelInput.java index 72015b009947..a360c1455602 100644 --- a/core/src/main/java/org/apache/calcite/rel/RelInput.java +++ b/core/src/main/java/org/apache/calcite/rel/RelInput.java @@ -27,6 +27,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -51,20 +53,20 @@ public interface RelInput { /** * Returns an expression. */ - RexNode getExpression(String tag); + @Nullable RexNode getExpression(String tag); ImmutableBitSet getBitSet(String tag); - List getBitSetList(String tag); + @Nullable List getBitSetList(String tag); List getAggregateCalls(String tag); - Object get(String tag); + @Nullable Object get(String tag); /** * Returns a {@code string} value. Throws if wrong type. */ - String getString(String tag); + @Nullable String getString(String tag); /** * Returns a {@code float} value. Throws if not present or wrong type. @@ -74,15 +76,15 @@ public interface RelInput { /** * Returns an enum value. Throws if not a valid member. */ - > E getEnum(String tag, Class enumClass); + > @Nullable E getEnum(String tag, Class enumClass); - List getExpressionList(String tag); + @Nullable List getExpressionList(String tag); - List getStringList(String tag); + @Nullable List getStringList(String tag); - List getIntegerList(String tag); + @Nullable List getIntegerList(String tag); - List> getIntegerListList(String tag); + @Nullable List> getIntegerListList(String tag); RelDataType getRowType(String tag); 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 d3ef79991c1f..42be83d5d935 100644 --- a/core/src/main/java/org/apache/calcite/rel/RelNode.java +++ b/core/src/main/java/org/apache/calcite/rel/RelNode.java @@ -35,6 +35,7 @@ import org.apiguardian.api.API; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; import java.util.List; import java.util.Set; @@ -89,6 +90,7 @@ public interface RelNode extends RelOptNode, Cloneable { * * @return this RelNode's CallingConvention */ + @Pure @Nullable Convention getConvention(); /** 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 70f8a615fa81..0f7fdab14a7b 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 @@ -124,7 +124,7 @@ protected ConverterRule(Class clazz, //~ Methods ---------------------------------------------------------------- - @Override public @Nullable Convention getOutConvention() { + @Override public Convention getOutConvention() { return (Convention) outTrait; } diff --git a/core/src/main/java/org/apache/calcite/rel/core/Collect.java b/core/src/main/java/org/apache/calcite/rel/core/Collect.java index d50b4d102342..d44613b13df4 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/Collect.java +++ b/core/src/main/java/org/apache/calcite/rel/core/Collect.java @@ -29,6 +29,8 @@ import java.util.List; +import static java.util.Objects.requireNonNull; + /** * A relational expression that collapses multiple rows into one. * @@ -69,7 +71,7 @@ public Collect( */ public Collect(RelInput input) { this(input.getCluster(), input.getTraitSet(), input.getInput(), - input.getString("field")); + requireNonNull(input.getString("field"), "field")); } //~ Methods ---------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/core/Correlate.java b/core/src/main/java/org/apache/calcite/rel/core/Correlate.java index c8f25a55816d..502b9deba4aa 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/Correlate.java +++ b/core/src/main/java/org/apache/calcite/rel/core/Correlate.java @@ -37,9 +37,10 @@ import org.checkerframework.checker.nullness.qual.Nullable; import java.util.List; -import java.util.Objects; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** * A relational operator that performs nested-loop joins. * @@ -96,9 +97,9 @@ protected Correlate( JoinRelType joinType) { super(cluster, traitSet, left, right); assert !joinType.generatesNullsOnLeft() : "Correlate has invalid join type " + joinType; - this.joinType = Objects.requireNonNull(joinType); - this.correlationId = Objects.requireNonNull(correlationId); - this.requiredColumns = Objects.requireNonNull(requiredColumns); + this.joinType = requireNonNull(joinType); + this.correlationId = requireNonNull(correlationId); + this.requiredColumns = requireNonNull(requiredColumns); } /** @@ -110,9 +111,10 @@ protected Correlate(RelInput input) { this( input.getCluster(), input.getTraitSet(), input.getInputs().get(0), input.getInputs().get(1), - new CorrelationId((Integer) input.get("correlation")), + new CorrelationId( + requireNonNull((Integer) input.get("correlation"), "correlation")), input.getBitSet("requiredColumns"), - input.getEnum("joinType", JoinRelType.class)); + requireNonNull(input.getEnum("joinType", JoinRelType.class), "joinType")); } //~ Methods ---------------------------------------------------------------- @@ -172,7 +174,7 @@ public CorrelationId getCorrelationId() { return correlationId; } - @Override public @Nullable String getCorrelVariable() { + @Override public String getCorrelVariable() { return correlationId.getName(); } @@ -213,13 +215,13 @@ public ImmutableBitSet getRequiredColumns() { Double restartCount = mq.getRowCount(getLeft()); if (restartCount == null) { - return null; + return planner.getCostFactory().makeInfiniteCost(); } // RelMetadataQuery.getCumulativeCost(getRight()); does not work for // RelSubset, so we ask planner to cost-estimate right relation RelOptCost rightCost = planner.getCost(getRight(), mq); if (rightCost == null) { - return null; + return planner.getCostFactory().makeInfiniteCost(); } RelOptCost rescanCost = rightCost.multiplyBy(Math.max(1.0, restartCount - 1)); 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 16abe169e82a..c3653353e3af 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 @@ -42,6 +42,8 @@ import java.util.List; import java.util.Objects; +import static java.util.Objects.requireNonNull; + /** * Relational expression that iterates over its input * and returns elements for which condition evaluates to @@ -75,9 +77,8 @@ protected Filter( RelNode child, RexNode condition) { super(cluster, traits, child); - assert condition != null; - assert RexUtil.isFlat(condition) : condition; - this.condition = condition; + this.condition = requireNonNull(condition, "condition"); + assert RexUtil.isFlat(condition) : "RexUtil.isFlat should be true for condition " + condition; // Too expensive for everyday use: assert !CalciteSystemProperty.DEBUG.value() || isValid(Litmus.THROW, null); } @@ -87,7 +88,7 @@ protected Filter( */ protected Filter(RelInput input) { this(input.getCluster(), input.getTraitSet(), input.getInput(), - input.getExpression("condition")); + requireNonNull(input.getExpression("condition"), "condition")); } //~ Methods ---------------------------------------------------------------- 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 855deab9fd04..bf882079444a 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 @@ -55,6 +55,8 @@ import java.util.Objects; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** * Relational expression that computes a set of * 'select expressions' from its input relational expression. @@ -117,7 +119,7 @@ protected Project(RelInput input) { input.getTraitSet(), ImmutableList.of(), input.getInput(), - input.getExpressionList("exprs"), + requireNonNull(input.getExpressionList("exprs"), "exprs"), input.getRowType("exprs", "fields")); } diff --git a/core/src/main/java/org/apache/calcite/rel/core/Sample.java b/core/src/main/java/org/apache/calcite/rel/core/Sample.java index bab6e2c805ca..3b5bff1c069a 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/Sample.java +++ b/core/src/main/java/org/apache/calcite/rel/core/Sample.java @@ -62,8 +62,8 @@ private static RelOptSamplingParameters getSamplingParameters( Object repeatableSeed = input.get("repeatableSeed"); boolean repeatable = repeatableSeed instanceof Number; return new RelOptSamplingParameters( - mode.equals("bernoulli"), percentage, repeatable, - repeatable ? ((Number) repeatableSeed).intValue() : 0); + "bernoulli".equals(mode), percentage, repeatable, + repeatable && repeatableSeed != null ? ((Number) repeatableSeed).intValue() : 0); } @Override public RelNode copy(RelTraitSet traitSet, List inputs) { 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 11bbfe9bdac5..987233b36efc 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 @@ -39,6 +39,8 @@ import java.util.List; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** * Relational expression that calls a table-valued function. * @@ -96,7 +98,8 @@ protected TableFunctionScan( protected TableFunctionScan(RelInput input) { this( input.getCluster(), input.getTraitSet(), input.getInputs(), - input.getExpression("invocation"), (Type) input.get("elementType"), + requireNonNull(input.getExpression("invocation"), "invocation"), + (Type) input.get("elementType"), input.getRowType("rowType"), ImmutableSet.of()); } 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 494078ac5e3f..6bfe699b0955 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 @@ -19,6 +19,7 @@ import org.apache.calcite.plan.RelOptCluster; import org.apache.calcite.plan.RelOptCost; import org.apache.calcite.plan.RelOptPlanner; +import org.apache.calcite.plan.RelOptSchema; import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.plan.RelOptUtil; import org.apache.calcite.plan.RelTraitSet; @@ -41,7 +42,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; import java.util.List; -import java.util.Objects; + +import static java.util.Objects.requireNonNull; /** * Relational expression that modifies a table. @@ -122,20 +124,21 @@ protected TableModify( this.updateColumnList = updateColumnList; this.sourceExpressionList = sourceExpressionList; if (operation == Operation.UPDATE) { - Objects.requireNonNull(updateColumnList); - Objects.requireNonNull(sourceExpressionList); + requireNonNull(updateColumnList); + requireNonNull(sourceExpressionList); Preconditions.checkArgument(sourceExpressionList.size() == updateColumnList.size()); } else { if (operation == Operation.MERGE) { - Objects.requireNonNull(updateColumnList); + requireNonNull(updateColumnList); } else { Preconditions.checkArgument(updateColumnList == null); } Preconditions.checkArgument(sourceExpressionList == null); } - if (table.getRelOptSchema() != null) { - cluster.getPlanner().registerSchema(table.getRelOptSchema()); + RelOptSchema relOptSchema = table.getRelOptSchema(); + if (relOptSchema != null) { + cluster.getPlanner().registerSchema(relOptSchema); } this.flattened = flattened; } @@ -147,9 +150,11 @@ protected TableModify(RelInput input) { this(input.getCluster(), input.getTraitSet(), input.getTable("table"), - (Prepare.CatalogReader) input.getTable("table").getRelOptSchema(), + (Prepare.CatalogReader) requireNonNull( + input.getTable("table").getRelOptSchema(), + "relOptSchema"), input.getInput(), - input.getEnum("operation", Operation.class), + requireNonNull(input.getEnum("operation", Operation.class), "operation"), input.getStringList("updateColumnList"), input.getExpressionList("sourceExpressionList"), input.getBoolean("flattened", false)); 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 7f6dd3599bc2..395a1358030d 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 @@ -19,6 +19,7 @@ import org.apache.calcite.plan.RelOptCluster; import org.apache.calcite.plan.RelOptCost; import org.apache.calcite.plan.RelOptPlanner; +import org.apache.calcite.plan.RelOptSchema; import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.plan.RelTraitSet; import org.apache.calcite.rel.AbstractRelNode; @@ -66,8 +67,9 @@ protected TableScan(RelOptCluster cluster, RelTraitSet traitSet, List hints, RelOptTable table) { super(cluster, traitSet); this.table = table; - if (table.getRelOptSchema() != null) { - cluster.getPlanner().registerSchema(table.getRelOptSchema()); + RelOptSchema relOptSchema = table.getRelOptSchema(); + if (relOptSchema != null) { + cluster.getPlanner().registerSchema(relOptSchema); } this.hints = ImmutableList.copyOf(hints); } diff --git a/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java b/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java index cbf5b6a89e3a..6a4c15e0a869 100644 --- a/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java +++ b/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java @@ -69,6 +69,7 @@ public Uncollect(RelOptCluster cluster, RelTraitSet traitSet, /** Creates an Uncollect. * *

Use {@link #create} unless you know what you're doing. */ + @SuppressWarnings("method.invocation.invalid") public Uncollect(RelOptCluster cluster, RelTraitSet traitSet, RelNode input, boolean withOrdinality, List itemAliases) { super(cluster, traitSet, input); @@ -162,8 +163,9 @@ public static RelDataType deriveUncollectRowType(RelNode rel, for (int i = 0; i < fields.size(); i++) { RelDataTypeField field = fields.get(i); if (field.getType() instanceof MapSqlType) { - builder.add(SqlUnnestOperator.MAP_KEY_COLUMN_NAME, field.getType().getKeyType()); - builder.add(SqlUnnestOperator.MAP_VALUE_COLUMN_NAME, field.getType().getValueType()); + MapSqlType mapType = (MapSqlType) field.getType(); + builder.add(SqlUnnestOperator.MAP_KEY_COLUMN_NAME, mapType.getKeyType()); + builder.add(SqlUnnestOperator.MAP_VALUE_COLUMN_NAME, mapType.getValueType()); } else { RelDataType ret = field.getType().getComponentType(); assert null != ret; diff --git a/core/src/main/java/org/apache/calcite/rel/externalize/RelDotWriter.java b/core/src/main/java/org/apache/calcite/rel/externalize/RelDotWriter.java index 16c8f7987b43..6ec4f9f8284d 100644 --- a/core/src/main/java/org/apache/calcite/rel/externalize/RelDotWriter.java +++ b/core/src/main/java/org/apache/calcite/rel/externalize/RelDotWriter.java @@ -38,7 +38,6 @@ import java.util.List; import java.util.Map; import java.util.function.Predicate; -import java.util.stream.Collectors; /** * Utility to dump a rel node plan in dot format. @@ -164,8 +163,8 @@ protected String getRelNodeLabel( return "\"" + String.join("\\n", newlabels) + "\""; } - private List getInputs(RelNode parent) { - return parent.getInputs().stream().map(child -> { + private List<@Nullable RelNode> getInputs(RelNode parent) { + return Util.transform(parent.getInputs(), child -> { if (child instanceof HepRelVertex) { return ((HepRelVertex) child).getCurrentRel(); } else if (child instanceof RelSubset) { @@ -174,10 +173,10 @@ private List getInputs(RelNode parent) { } else { return child; } - }).collect(Collectors.toList()); + }); } - private void explainInputs(List inputs) { + private void explainInputs(List inputs) { for (RelNode input : inputs) { if (input == null || nodeLabels.containsKey(input)) { continue; 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 23ff98edc98d..49a1fc310aa8 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,6 +65,7 @@ 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; @@ -86,7 +87,7 @@ */ public class RelJson { private final Map constructorMap = new HashMap<>(); - private final JsonBuilder jsonBuilder; + private final @Nullable JsonBuilder jsonBuilder; public static final List PACKAGES = ImmutableList.of( @@ -96,13 +97,29 @@ public class RelJson { "org.apache.calcite.adapter.jdbc.", "org.apache.calcite.adapter.jdbc.JdbcRules$"); - public RelJson(JsonBuilder jsonBuilder) { + public RelJson(@Nullable JsonBuilder jsonBuilder) { this.jsonBuilder = jsonBuilder; } + private JsonBuilder jsonBuilder() { + return requireNonNull(jsonBuilder, "jsonBuilder"); + } + + @SuppressWarnings("unchecked") + private T get(Map map, String key) { + return (T) requireNonNull(map.get(key), () -> "entry for key " + key); + } + + private > T enumVal(Class clazz, Map map, String key) { + String textValue = get(map, key); + return requireNonNull( + Util.enumVal(clazz, textValue), + () -> "unable to find enum value " + textValue + " in class " + clazz); + } + public RelNode create(Map map) { - String type = (String) map.get("type"); - Constructor constructor = getConstructor(requireNonNull(type, "type")); + String type = get(map, "type"); + Constructor constructor = getConstructor(type); try { return (RelNode) constructor.newInstance(map); } catch (InstantiationException | ClassCastException | InvocationTargetException @@ -168,7 +185,7 @@ public String classToTypeName(Class class_) { public Object toJson(RelCollationImpl node) { final List list = new ArrayList<>(); for (RelFieldCollation fieldCollation : node.getFieldCollations()) { - final Map map = jsonBuilder.map(); + final Map map = jsonBuilder().map(); map.put("field", fieldCollation.getFieldIndex()); map.put("direction", fieldCollation.getDirection().name()); map.put("nulls", fieldCollation.nullDirection.name()); @@ -189,18 +206,18 @@ public RelCollation toCollation( public RelFieldCollation toFieldCollation(Map map) { final Integer field = (Integer) map.get("field"); final RelFieldCollation.Direction direction = - Util.enumVal(RelFieldCollation.Direction.class, - (String) map.get("direction")); + enumVal(RelFieldCollation.Direction.class, + map, "direction"); final RelFieldCollation.NullDirection nullDirection = - Util.enumVal(RelFieldCollation.NullDirection.class, - (String) map.get("nulls")); + enumVal(RelFieldCollation.NullDirection.class, + map, "nulls"); return new RelFieldCollation(field, direction, nullDirection); } public RelDistribution toDistribution(Map map) { final RelDistribution.Type type = - Util.enumVal(RelDistribution.Type.class, - (String) map.get("type")); + enumVal(RelDistribution.Type.class, + map, "type"); ImmutableIntList list = EMPTY; if (map.containsKey("keys")) { @@ -211,7 +228,7 @@ public RelDistribution toDistribution(Map map) { } private Object toJson(RelDistribution relDistribution) { - final Map map = jsonBuilder.map(); + final Map map = jsonBuilder().map(); map.put("type", relDistribution.getType().name()); if (!relDistribution.getKeys().isEmpty()) { map.put("keys", relDistribution.getKeys()); @@ -237,7 +254,7 @@ public RelDataType toType(RelDataTypeFactory typeFactory, Object o) { return toType(typeFactory, fields); } else { final SqlTypeName sqlTypeName = - Util.enumVal(SqlTypeName.class, (String) map.get("type")); + enumVal(SqlTypeName.class, map, "type"); final Integer precision = (Integer) map.get("precision"); final Integer scale = (Integer) map.get("scale"); if (SqlTypeName.INTERVAL_TYPES.contains(sqlTypeName)) { @@ -256,18 +273,19 @@ public RelDataType toType(RelDataTypeFactory typeFactory, Object o) { } else { type = typeFactory.createSqlType(sqlTypeName, precision, scale); } - final boolean nullable = (Boolean) map.get("nullable"); + final boolean nullable = get(map, "nullable"); return typeFactory.createTypeWithNullability(type, nullable); } } else { - final SqlTypeName sqlTypeName = - Util.enumVal(SqlTypeName.class, (String) o); + final SqlTypeName sqlTypeName = requireNonNull( + Util.enumVal(SqlTypeName.class, (String) o), + () -> "unable to find enum value " + o + " in class " + SqlTypeName.class); return typeFactory.createSqlType(sqlTypeName); } } public Object toJson(AggregateCall node) { - final Map map = jsonBuilder.map(); + final Map map = jsonBuilder().map(); final Map aggMap = toJson(node.getAggregation()); if (node.getAggregation().getFunctionType().isUserDefined()) { aggMap.put("class", node.getAggregation().getClass().getName()); @@ -297,13 +315,13 @@ public Object toJson(AggregateCall node) { } else if (value instanceof CorrelationId) { return toJson((CorrelationId) value); } else if (value instanceof List) { - final List<@Nullable Object> list = jsonBuilder.list(); - for (Object o : (List) value) { + final List<@Nullable Object> list = jsonBuilder().list(); + for (Object o : (List) value) { list.add(toJson(o)); } return list; } else if (value instanceof ImmutableBitSet) { - final List<@Nullable Object> list = jsonBuilder.list(); + final List<@Nullable Object> list = jsonBuilder().list(); for (Integer integer : (ImmutableBitSet) value) { list.add(toJson(integer)); } @@ -326,13 +344,13 @@ public Object toJson(AggregateCall node) { private Object toJson(RelDataType node) { if (node.isStruct()) { - final List<@Nullable Object> list = jsonBuilder.list(); + final List<@Nullable Object> list = jsonBuilder().list(); for (RelDataTypeField field : node.getFieldList()) { list.add(toJson(field)); } return list; } else { - final Map map = jsonBuilder.map(); + final Map map = jsonBuilder().map(); map.put("type", node.getSqlTypeName().name()); map.put("nullable", node.isNullable()); if (node.getSqlTypeName().allowsPrec()) { @@ -348,7 +366,7 @@ private Object toJson(RelDataType node) { private Object toJson(RelDataTypeField node) { final Map map; if (node.getType().isStruct()) { - map = jsonBuilder.map(); + map = jsonBuilder().map(); map.put("fields", toJson(node.getType())); } else { map = (Map) toJson(node.getType()); @@ -365,7 +383,7 @@ private Object toJson(RexNode node) { final Map map; switch (node.getKind()) { case FIELD_ACCESS: - map = jsonBuilder.map(); + map = jsonBuilder().map(); final RexFieldAccess fieldAccess = (RexFieldAccess) node; map.put("field", fieldAccess.getField().getName()); map.put("expr", toJson(fieldAccess.getReferenceExpr())); @@ -373,32 +391,32 @@ private Object toJson(RexNode node) { case LITERAL: final RexLiteral literal = (RexLiteral) node; final Object value = literal.getValue3(); - map = jsonBuilder.map(); + map = jsonBuilder().map(); map.put("literal", RelEnumTypes.fromEnum(value)); map.put("type", toJson(node.getType())); return map; case INPUT_REF: - map = jsonBuilder.map(); + map = jsonBuilder().map(); map.put("input", ((RexSlot) node).getIndex()); map.put("name", ((RexSlot) node).getName()); return map; case LOCAL_REF: - map = jsonBuilder.map(); + map = jsonBuilder().map(); map.put("input", ((RexSlot) node).getIndex()); map.put("name", ((RexSlot) node).getName()); map.put("type", toJson(node.getType())); return map; case CORREL_VARIABLE: - map = jsonBuilder.map(); + map = jsonBuilder().map(); map.put("correl", ((RexCorrelVariable) node).getName()); map.put("type", toJson(node.getType())); return map; default: if (node instanceof RexCall) { final RexCall call = (RexCall) node; - map = jsonBuilder.map(); + map = jsonBuilder().map(); map.put("op", toJson(call.getOperator())); - final List<@Nullable Object> list = jsonBuilder.list(); + final List<@Nullable Object> list = jsonBuilder().list(); for (RexNode operand : call.getOperands()) { list.add(toJson(operand)); } @@ -432,7 +450,7 @@ private Object toJson(RexNode node) { } private Object toJson(RexWindow window) { - final Map map = jsonBuilder.map(); + final Map map = jsonBuilder().map(); if (window.partitionKeys.size() > 0) { map.put("partition", toJson(window.partitionKeys)); } @@ -460,7 +478,7 @@ private Object toJson(RexWindow window) { } private Object toJson(RexFieldCollation collation) { - final Map map = jsonBuilder.map(); + final Map map = jsonBuilder().map(); map.put("expr", toJson(collation.left)); map.put("direction", collation.getDirection().name()); map.put("null-direction", collation.getNullDirection().name()); @@ -468,19 +486,21 @@ private Object toJson(RexFieldCollation collation) { } private Object toJson(RexWindowBound windowBound) { - final Map map = jsonBuilder.map(); + final Map map = jsonBuilder().map(); if (windowBound.isCurrentRow()) { map.put("type", "CURRENT_ROW"); } else if (windowBound.isUnbounded()) { map.put("type", windowBound.isPreceding() ? "UNBOUNDED_PRECEDING" : "UNBOUNDED_FOLLOWING"); } else { map.put("type", windowBound.isPreceding() ? "PRECEDING" : "FOLLOWING"); - map.put("offset", toJson(windowBound.getOffset())); + RexNode offset = requireNonNull(windowBound.getOffset(), + () -> "getOffset for window bound " + windowBound); + map.put("offset", toJson(offset)); } return map; } - @Nullable RexNode toRex(RelInput relInput, @Nullable Object o) { + @PolyNull RexNode toRex(RelInput relInput, @PolyNull Object o) { final RelOptCluster cluster = relInput.getCluster(); final RexBuilder rexBuilder = cluster.getRexBuilder(); if (o == null) { @@ -493,7 +513,8 @@ private Object toJson(RexWindowBound windowBound) { if (map.containsKey("class")) { opMap.put("class", map.get("class")); } - final List operands = (List) map.get("operands"); + @SuppressWarnings("unchecked") + final List operands = get((Map) map, "operands"); final List rexOperands = toRexList(relInput, operands); final Object jsonType = map.get("type"); final Map window = (Map) map.get("window"); @@ -521,13 +542,17 @@ private Object toJson(RexWindowBound windowBound) { physical = false; } else { // No ROWS or RANGE clause + // Note: lower and upper bounds are non-nullable, so this branch is not reachable lowerBound = null; upperBound = null; physical = false; } - final boolean distinct = (Boolean) map.get("distinct"); + final boolean distinct = get((Map) map, "distinct"); return rexBuilder.makeOver(type, operator, rexOperands, partitionKeys, - ImmutableList.copyOf(orderKeys), lowerBound, upperBound, physical, + ImmutableList.copyOf(orderKeys), + requireNonNull(lowerBound, "lowerBound"), + requireNonNull(upperBound, "upperBound"), + physical, true, false, distinct, false); } else { final SqlOperator operator = requireNonNull(toOp(opMap), "operator"); @@ -636,7 +661,7 @@ private void addRexFieldCollationList( return null; } - final String type = (String) map.get("type"); + final String type = get(map, "type"); switch (type) { case "CURRENT_ROW": return RexWindowBounds.CURRENT_ROW; @@ -691,9 +716,9 @@ private List toRexList(RelInput relInput, List operands) { return (SqlAggFunction) toOp(map); } - private Map toJson(SqlOperator operator) { + private Map toJson(SqlOperator operator) { // User-defined operators are not yet handled. - Map map = jsonBuilder.map(); + Map map = jsonBuilder().map(); map.put("name", operator.getName()); map.put("kind", operator.kind.toString()); map.put("syntax", operator.getSyntax().toString()); diff --git a/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java b/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java index d4fa8868ccbe..3fcc3c60095f 100644 --- a/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java +++ b/core/src/main/java/org/apache/calcite/rel/externalize/RelJsonReader.java @@ -53,6 +53,8 @@ import java.util.Locale; import java.util.Map; +import static java.util.Objects.requireNonNull; + /** * Reads a JSON plan and converts it back to a tree of relational expressions. * @@ -85,7 +87,7 @@ public RelNode read(String s) throws IOException { @SuppressWarnings("unchecked") final List> rels = (List) o.get("rels"); readRels(rels); - return lastRel; + return requireNonNull(lastRel, "lastRel"); } private void readRels(List> jsonRels) { @@ -108,8 +110,12 @@ private void readRel(final Map jsonRel) { } @Override public RelOptTable getTable(String table) { - final List list = getStringList(table); - return relOptSchema.getTableForMember(list); + final List list = requireNonNull( + getStringList(table), + () -> "getStringList for " + table); + return requireNonNull( + relOptSchema.getTableForMember(list), + () -> "table " + table + " is not found in schema " + relOptSchema.toString()); } @Override public RelNode getInput() { @@ -121,7 +127,7 @@ private void readRel(final Map jsonRel) { @Override public List getInputs() { final List jsonInputs = getStringList("inputs"); if (jsonInputs == null) { - return ImmutableList.of(lastRel); + return ImmutableList.of(requireNonNull(lastRel, "lastRel")); } final ImmutableList.Builder inputs = new ImmutableList.Builder<>(); for (String jsonInput : jsonInputs) { @@ -130,15 +136,15 @@ private void readRel(final Map jsonRel) { return inputs.build(); } - @Override public RexNode getExpression(String tag) { + @Override public @Nullable RexNode getExpression(String tag) { return relJson.toRex(this, jsonRel.get(tag)); } @Override public ImmutableBitSet getBitSet(String tag) { - return ImmutableBitSet.of(getIntegerList(tag)); + return ImmutableBitSet.of(requireNonNull(getIntegerList(tag), tag)); } - @Override public List getBitSetList(String tag) { + @Override public @Nullable List getBitSetList(String tag) { List> list = getIntegerListList(tag); if (list == null) { return null; @@ -151,17 +157,17 @@ private void readRel(final Map jsonRel) { return builder.build(); } - @Override public List getStringList(String tag) { + @Override public @Nullable List getStringList(String tag) { //noinspection unchecked return (List) jsonRel.get(tag); } - @Override public List getIntegerList(String tag) { + @Override public @Nullable List getIntegerList(String tag) { //noinspection unchecked return (List) jsonRel.get(tag); } - @Override public List> getIntegerListList(String tag) { + @Override public @Nullable List> getIntegerListList(String tag) { //noinspection unchecked return (List>) jsonRel.get(tag); } @@ -176,29 +182,33 @@ private void readRel(final Map jsonRel) { return inputs; } - @Override public Object get(String tag) { + @Override public @Nullable Object get(String tag) { return jsonRel.get(tag); } - @Override public String getString(String tag) { - return (String) jsonRel.get(tag); + private Object getNonNull(String tag) { + return requireNonNull(get(tag), () -> "no entry for tag " + tag); + } + + @Override public @Nullable String getString(String tag) { + return (String) get(tag); } @Override public float getFloat(String tag) { - return ((Number) jsonRel.get(tag)).floatValue(); + return ((Number) getNonNull(tag)).floatValue(); } @Override public boolean getBoolean(String tag, boolean default_) { - final Boolean b = (Boolean) jsonRel.get(tag); + final Boolean b = (Boolean) get(tag); return b != null ? b : default_; } - @Override public > E getEnum(String tag, Class enumClass) { + @Override public > @Nullable E getEnum(String tag, Class enumClass) { return Util.enumVal(enumClass, - getString(tag).toUpperCase(Locale.ROOT)); + ((String) getNonNull(tag)).toUpperCase(Locale.ROOT)); } - @Override public List getExpressionList(String tag) { + @Override public @Nullable List getExpressionList(String tag) { @SuppressWarnings("unchecked") final List jsonNodes = (List) jsonRel.get(tag); if (jsonNodes == null) { @@ -212,19 +222,19 @@ private void readRel(final Map jsonRel) { } @Override public RelDataType getRowType(String tag) { - final Object o = jsonRel.get(tag); + final Object o = getNonNull(tag); return relJson.toType(cluster.getTypeFactory(), o); } @Override public RelDataType getRowType(String expressionsTag, String fieldsTag) { final List expressionList = getExpressionList(expressionsTag); @SuppressWarnings("unchecked") final List names = - (List) get(fieldsTag); + (List) getNonNull(fieldsTag); return cluster.getTypeFactory().createStructType( new AbstractList>() { @Override public Map.Entry get(int index) { return Pair.of(names.get(index), - expressionList.get(index).getType()); + requireNonNull(expressionList, "expressionList").get(index).getType()); } @Override public int size() { @@ -235,16 +245,17 @@ private void readRel(final Map jsonRel) { @Override public RelCollation getCollation() { //noinspection unchecked - return relJson.toCollation((List) get("collation")); + return relJson.toCollation((List) getNonNull("collation")); } @Override public RelDistribution getDistribution() { - return relJson.toDistribution((Map) get("distribution")); + //noinspection unchecked + return relJson.toDistribution((Map) getNonNull("distribution")); } @Override public ImmutableList> getTuples(String tag) { //noinspection unchecked - final List jsonTuples = (List) get(tag); + final List jsonTuples = (List) getNonNull(tag); final ImmutableList.Builder> builder = ImmutableList.builder(); for (List jsonTuple : jsonTuples) { @@ -278,9 +289,13 @@ public ImmutableList getTuple(List jsonTuple) { } private AggregateCall toAggCall(Map jsonAggCall) { - final Map aggMap = (Map) jsonAggCall.get("agg"); - final SqlAggFunction aggregation = - relJson.toAggregation(aggMap); + @SuppressWarnings("unchecked") + final Map aggMap = (Map) requireNonNull( + jsonAggCall.get("agg"), + "agg key is not found"); + final SqlAggFunction aggregation = requireNonNull( + relJson.toAggregation(aggMap), + () -> "relJson.toAggregation output for " + aggMap); final Boolean distinct = (Boolean) jsonAggCall.get("distinct"); @SuppressWarnings("unchecked") final List operands = (List) jsonAggCall.get("operands"); diff --git a/core/src/main/java/org/apache/calcite/rel/externalize/RelXmlWriter.java b/core/src/main/java/org/apache/calcite/rel/externalize/RelXmlWriter.java index 7d293cc876ff..7078f9add18d 100644 --- a/core/src/main/java/org/apache/calcite/rel/externalize/RelXmlWriter.java +++ b/core/src/main/java/org/apache/calcite/rel/externalize/RelXmlWriter.java @@ -26,6 +26,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Callback for a relational expression to dump in XML format. @@ -138,18 +139,18 @@ private void explainGeneric( */ private void explainSpecific( RelNode rel, - List> values) { + List> values) { String tagName = rel.getRelTypeName(); xmlOutput.beginBeginTag(tagName); xmlOutput.attribute("id", rel.getId() + ""); - for (Pair value : values) { + for (Pair value : values) { if (value.right instanceof RelNode) { continue; } xmlOutput.attribute( value.left, - value.right.toString()); + Objects.toString(value.right)); } xmlOutput.endBeginTag(tagName); spacer.add(2); 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 63a89abccb24..c36e64b30c52 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 @@ -23,6 +23,7 @@ import org.apache.calcite.util.trace.CalciteTrace; import com.google.common.collect.ImmutableMap; + import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java index 031de6483f89..8a4a3f193d92 100644 --- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java +++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java @@ -29,6 +29,8 @@ import org.apache.calcite.util.ImmutableBitSet; import org.apache.calcite.util.Litmus; +import static java.util.Objects.requireNonNull; + /** * A relational operator that performs nested-loop joins. * @@ -80,9 +82,10 @@ public LogicalCorrelate( public LogicalCorrelate(RelInput input) { this(input.getCluster(), input.getTraitSet(), input.getInputs().get(0), input.getInputs().get(1), - new CorrelationId((Integer) input.get("correlation")), + new CorrelationId( + (Integer) requireNonNull(input.get("correlation"), "correlation")), input.getBitSet("requiredColumns"), - input.getEnum("joinType", JoinRelType.class)); + requireNonNull(input.getEnum("joinType", JoinRelType.class), "joinType")); } /** Creates a LogicalCorrelate. */ 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 fa3a9c8ef940..44704a534c0d 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 @@ -40,6 +40,8 @@ import java.util.Objects; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** * Sub-class of {@link org.apache.calcite.rel.core.Join} * not targeted at any particular engine or calling convention. @@ -103,7 +105,7 @@ public LogicalJoin( ImmutableList systemFieldList) { super(cluster, traitSet, hints, left, right, condition, variablesSet, joinType); this.semiJoinDone = semiJoinDone; - this.systemFieldList = Objects.requireNonNull(systemFieldList); + this.systemFieldList = requireNonNull(systemFieldList); } @Deprecated // to be removed before 2.0 @@ -149,8 +151,10 @@ public LogicalJoin(RelInput input) { this(input.getCluster(), input.getCluster().traitSetOf(Convention.NONE), new ArrayList<>(), input.getInputs().get(0), input.getInputs().get(1), - input.getExpression("condition"), ImmutableSet.of(), - input.getEnum("joinType", JoinRelType.class), false, + requireNonNull(input.getExpression("condition"), "condition"), + ImmutableSet.of(), + requireNonNull(input.getEnum("joinType", JoinRelType.class), "joinType"), + false, ImmutableList.of()); } 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 273f7a2f28eb..92e242a1dae3 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 @@ -57,11 +57,11 @@ public interface Selectivity extends Metadata { * @return estimated selectivity (between 0.0 and 1.0), or null if no * reliable estimate can be determined */ - @Nullable Double getSelectivity(RexNode predicate); + @Nullable Double getSelectivity(@Nullable RexNode predicate); /** Handler API. */ interface Handler extends MetadataHandler { - @Nullable Double getSelectivity(RelNode r, RelMetadataQuery mq, RexNode predicate); + @Nullable Double getSelectivity(RelNode r, RelMetadataQuery mq, @Nullable RexNode predicate); } } diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/CachingRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/rel/metadata/CachingRelMetadataProvider.java index 4d76dd1de886..37dcff3d921b 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/CachingRelMetadataProvider.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/CachingRelMetadataProvider.java @@ -59,7 +59,7 @@ public CachingRelMetadataProvider( //~ Methods ---------------------------------------------------------------- - @Override public @Nullable UnboundMetadata apply( + @Override public <@Nullable M extends @Nullable Metadata> @Nullable UnboundMetadata apply( Class relClass, final Class metadataClass) { final UnboundMetadata function = diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/ChainedRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/rel/metadata/ChainedRelMetadataProvider.java index d04c292a991f..cfed31146d0e 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/ChainedRelMetadataProvider.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/ChainedRelMetadataProvider.java @@ -69,7 +69,7 @@ protected ChainedRelMetadataProvider( return providers.hashCode(); } - @Override public @Nullable UnboundMetadata apply( + @Override public <@Nullable M extends @Nullable Metadata> @Nullable UnboundMetadata apply( Class relClass, final Class metadataClass) { final List> functions = new ArrayList<>(); @@ -127,7 +127,7 @@ private static class ChainedInvocationHandler implements InvocationHandler { this.metadataList = ImmutableList.copyOf(metadataList); } - @Override public Object invoke(Object proxy, Method method, Object[] args) + @Override public @Nullable Object invoke(Object proxy, Method method, Object[] args) throws Throwable { for (Metadata metadata : metadataList) { try { diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/JaninoRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/rel/metadata/JaninoRelMetadataProvider.java index 03e08f63a1ed..76106c9389a9 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/JaninoRelMetadataProvider.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/JaninoRelMetadataProvider.java @@ -182,7 +182,7 @@ private static CacheBuilder maxSize(CacheBuilder builder, return 109 + provider.hashCode(); } - @Override public @Nullable UnboundMetadata apply( + @Override public <@Nullable M extends @Nullable Metadata> UnboundMetadata apply( Class relClass, Class metadataClass) { throw new UnsupportedOperationException(); } diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/MetadataFactory.java b/core/src/main/java/org/apache/calcite/rel/metadata/MetadataFactory.java index 24b3e4f4c3ff..40a66f1a567a 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/MetadataFactory.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/MetadataFactory.java @@ -18,6 +18,8 @@ import org.apache.calcite.rel.RelNode; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Source of metadata about relational expressions. * @@ -40,6 +42,6 @@ public interface MetadataFactory { * @param metadataClazz Metadata class * @return Metadata bound to {@code rel} and {@code query} */ - M query(RelNode rel, RelMetadataQuery mq, + M query(RelNode rel, RelMetadataQuery mq, Class metadataClazz); } diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/MetadataFactoryImpl.java b/core/src/main/java/org/apache/calcite/rel/metadata/MetadataFactoryImpl.java index d92c267bd8c7..923c6d64b1fc 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/MetadataFactoryImpl.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/MetadataFactoryImpl.java @@ -25,9 +25,12 @@ import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.UncheckedExecutionException; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.concurrent.ExecutionException; -/** Implementation of {@link MetadataFactory} that gets providers from a +/** + * Implementation of {@link MetadataFactory} that gets providers from a * {@link RelMetadataProvider} and stores them in a cache. * *

The cache does not store metadata. It remembers which providers can @@ -36,30 +39,31 @@ */ public class MetadataFactoryImpl implements MetadataFactory { @SuppressWarnings("unchecked") - public static final UnboundMetadata DUMMY = (rel, mq) -> null; + public static final UnboundMetadata<@Nullable Metadata> DUMMY = (rel, mq) -> null; private final LoadingCache< - Pair, Class>, UnboundMetadata> cache; + Pair, ? extends Class>, + UnboundMetadata<@Nullable Metadata>> cache; public MetadataFactoryImpl(RelMetadataProvider provider) { this.cache = CacheBuilder.newBuilder().build(loader(provider)); } - private static CacheLoader, Class>, - UnboundMetadata> loader(final RelMetadataProvider provider) { + private static CacheLoader, ? extends Class>, + UnboundMetadata<@Nullable Metadata>> loader(final RelMetadataProvider provider) { return CacheLoader.from(key -> { - final UnboundMetadata function = + final UnboundMetadata<@Nullable Metadata> function = provider.apply(key.left, key.right); // Return DUMMY, not null, so the cache knows to not ask again. return function != null ? function : DUMMY; }); } - @Override public M query(RelNode rel, RelMetadataQuery mq, + @Override public M query(RelNode rel, RelMetadataQuery mq, Class metadataClazz) { try { //noinspection unchecked - final Pair, Class> key = + final Pair, Class> key = (Pair) Pair.of(rel.getClass(), metadataClazz); final Metadata apply = cache.get(key).bind(rel, mq); return metadataClazz.cast(apply); diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java index 38a51934187c..2dae2be42de8 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java @@ -230,7 +230,7 @@ private static boolean couldImplement(Method handlerMethod, Method method) { //~ Methods ---------------------------------------------------------------- - @Override public @Nullable UnboundMetadata apply( + @Override public <@Nullable M extends @Nullable Metadata> @Nullable UnboundMetadata apply( Class relClass, Class metadataClass) { if (metadataClass == metadataClass0) { return apply(relClass); @@ -240,7 +240,7 @@ private static boolean couldImplement(Method handlerMethod, Method method) { } @SuppressWarnings({ "unchecked", "SuspiciousMethodCalls" }) - public @Nullable UnboundMetadata apply( + public <@Nullable M extends @Nullable Metadata> @Nullable UnboundMetadata apply( Class relClass) { List> newSources = new ArrayList<>(); for (;;) { diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java index dd54e86182b4..37a4fbd197e3 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java @@ -61,6 +61,8 @@ import com.google.common.collect.Multimap; import com.google.common.collect.Ordering; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -111,21 +113,21 @@ private RelMdCollation() {} * * @see org.apache.calcite.rel.metadata.RelMetadataQuery#collations(RelNode) */ - public ImmutableList collations(RelNode rel, + public @Nullable ImmutableList collations(RelNode rel, RelMetadataQuery mq) { return null; } - private static ImmutableList copyOf(Collection values) { + private static @Nullable ImmutableList copyOf(@Nullable Collection values) { return values == null ? null : ImmutableList.copyOf(values); } - public ImmutableList collations(Window rel, + public @Nullable ImmutableList collations(Window rel, RelMetadataQuery mq) { return copyOf(window(mq, rel.getInput(), rel.groups)); } - public ImmutableList collations(Match rel, + public @Nullable ImmutableList collations(Match rel, RelMetadataQuery mq) { return copyOf( match(mq, rel.getInput(), rel.getRowType(), rel.getPattern(), @@ -135,22 +137,22 @@ public ImmutableList collations(Match rel, rel.getOrderKeys(), rel.getInterval())); } - public ImmutableList collations(Filter rel, + public @Nullable ImmutableList collations(Filter rel, RelMetadataQuery mq) { return mq.collations(rel.getInput()); } - public ImmutableList collations(TableModify rel, + public @Nullable ImmutableList collations(TableModify rel, RelMetadataQuery mq) { return mq.collations(rel.getInput()); } - public ImmutableList collations(TableScan scan, + public @Nullable ImmutableList collations(TableScan scan, RelMetadataQuery mq) { return copyOf(table(scan.getTable())); } - public ImmutableList collations(EnumerableMergeJoin join, + public @Nullable ImmutableList collations(EnumerableMergeJoin join, RelMetadataQuery mq) { // In general a join is not sorted. But a merge join preserves the sort // order of the left and right sides. @@ -160,66 +162,66 @@ public ImmutableList collations(EnumerableMergeJoin join, join.getJoinType())); } - public ImmutableList collations(EnumerableHashJoin join, + public @Nullable ImmutableList collations(EnumerableHashJoin join, RelMetadataQuery mq) { return copyOf( RelMdCollation.enumerableHashJoin(mq, join.getLeft(), join.getRight(), join.getJoinType())); } - public ImmutableList collations(EnumerableNestedLoopJoin join, + public @Nullable ImmutableList collations(EnumerableNestedLoopJoin join, RelMetadataQuery mq) { return copyOf( RelMdCollation.enumerableNestedLoopJoin(mq, join.getLeft(), join.getRight(), join.getJoinType())); } - public ImmutableList collations(EnumerableCorrelate join, + public @Nullable ImmutableList collations(EnumerableCorrelate join, RelMetadataQuery mq) { return copyOf( RelMdCollation.enumerableCorrelate(mq, join.getLeft(), join.getRight(), join.getJoinType())); } - public ImmutableList collations(Sort sort, + public @Nullable ImmutableList collations(Sort sort, RelMetadataQuery mq) { return copyOf( RelMdCollation.sort(sort.getCollation())); } - public ImmutableList collations(SortExchange sort, + public @Nullable ImmutableList collations(SortExchange sort, RelMetadataQuery mq) { return copyOf( RelMdCollation.sort(sort.getCollation())); } - public ImmutableList collations(Project project, + public @Nullable ImmutableList collations(Project project, RelMetadataQuery mq) { return copyOf( project(mq, project.getInput(), project.getProjects())); } - public ImmutableList collations(Calc calc, + public @Nullable ImmutableList collations(Calc calc, RelMetadataQuery mq) { return copyOf(calc(mq, calc.getInput(), calc.getProgram())); } - public ImmutableList collations(Values values, + public @Nullable ImmutableList collations(Values values, RelMetadataQuery mq) { return copyOf( values(mq, values.getRowType(), values.getTuples())); } - public ImmutableList collations(JdbcToEnumerableConverter rel, + public @Nullable ImmutableList collations(JdbcToEnumerableConverter rel, RelMetadataQuery mq) { return mq.collations(rel.getInput()); } - public ImmutableList collations(HepRelVertex rel, + public @Nullable ImmutableList collations(HepRelVertex rel, RelMetadataQuery mq) { return mq.collations(rel.getCurrentRel()); } - public ImmutableList collations(RelSubset rel, + public @Nullable ImmutableList collations(RelSubset rel, RelMetadataQuery mq) { return copyOf( Objects.requireNonNull( @@ -230,13 +232,13 @@ public ImmutableList collations(RelSubset rel, /** Helper method to determine a * {@link org.apache.calcite.rel.core.TableScan}'s collation. */ - public static List table(RelOptTable table) { + public static @Nullable List table(RelOptTable table) { return table.getCollationList(); } /** Helper method to determine a * {@link org.apache.calcite.rel.core.Snapshot}'s collation. */ - public static List snapshot(RelMetadataQuery mq, RelNode input) { + public static @Nullable List snapshot(RelMetadataQuery mq, RelNode input) { return mq.collations(input); } @@ -248,19 +250,19 @@ public static List sort(RelCollation collation) { /** Helper method to determine a * {@link org.apache.calcite.rel.core.Filter}'s collation. */ - public static List filter(RelMetadataQuery mq, RelNode input) { + public static @Nullable List filter(RelMetadataQuery mq, RelNode input) { return mq.collations(input); } /** Helper method to determine a * limit's collation. */ - public static List limit(RelMetadataQuery mq, RelNode input) { + public static @Nullable List limit(RelMetadataQuery mq, RelNode input) { return mq.collations(input); } /** Helper method to determine a * {@link org.apache.calcite.rel.core.Calc}'s collation. */ - public static List calc(RelMetadataQuery mq, RelNode input, + public static @Nullable List calc(RelMetadataQuery mq, RelNode input, RexProgram program) { final List projects = program @@ -272,7 +274,7 @@ public static List calc(RelMetadataQuery mq, RelNode input, } /** Helper method to determine a {@link Project}'s collation. */ - public static List project(RelMetadataQuery mq, + public static @Nullable List project(RelMetadataQuery mq, RelNode input, List projects) { final NavigableSet collations = new TreeSet<>(); final List inputCollations = mq.collations(input); @@ -341,14 +343,14 @@ public static List project(RelMetadataQuery mq, * from each of its windows. Assuming (quite reasonably) that the * implementation does not re-order its input rows, then any collations of its * input are preserved. */ - public static List window(RelMetadataQuery mq, RelNode input, + public static @Nullable List window(RelMetadataQuery mq, RelNode input, ImmutableList groups) { return mq.collations(input); } /** Helper method to determine a * {@link org.apache.calcite.rel.core.Match}'s collation. */ - public static List match(RelMetadataQuery mq, RelNode input, + public static @Nullable List match(RelMetadataQuery mq, RelNode input, RelDataType rowType, RexNode pattern, boolean strictStart, boolean strictEnd, Map patternDefinitions, Map measures, @@ -441,7 +443,7 @@ public static Ordering> comparator( * key, the result preserves those collations too. * @deprecated Use {@link #mergeJoin(RelMetadataQuery, RelNode, RelNode, ImmutableIntList, ImmutableIntList, JoinRelType)} */ @Deprecated // to be removed before 2.0 - public static List mergeJoin(RelMetadataQuery mq, + public static @Nullable List mergeJoin(RelMetadataQuery mq, RelNode left, RelNode right, ImmutableIntList leftKeys, ImmutableIntList rightKeys) { return mergeJoin(mq, left, right, leftKeys, rightKeys, JoinRelType.INNER); @@ -452,7 +454,7 @@ public static List mergeJoin(RelMetadataQuery mq, * *

If the inputs are sorted on other keys in addition to the join * key, the result preserves those collations too. */ - public static List mergeJoin(RelMetadataQuery mq, + public static @Nullable List mergeJoin(RelMetadataQuery mq, RelNode left, RelNode right, ImmutableIntList leftKeys, ImmutableIntList rightKeys, JoinRelType joinType) { assert EnumerableMergeJoin.isMergeJoinSupported(joinType) @@ -462,11 +464,18 @@ public static List mergeJoin(RelMetadataQuery mq, if (!joinType.projectsRight()) { return leftCollations; } + if (leftCollations == null) { + return null; + } + + final ImmutableList rightCollations = mq.collations(right); + if (rightCollations == null) { + return leftCollations; + } final ImmutableList.Builder builder = ImmutableList.builder(); builder.addAll(leftCollations); - final ImmutableList rightCollations = mq.collations(right); final int leftFieldCount = left.getRowType().getFieldCount(); for (RelCollation collation : rightCollations) { builder.add(RelCollations.shift(collation, leftFieldCount)); @@ -477,7 +486,7 @@ public static List mergeJoin(RelMetadataQuery mq, /** * Returns the collation of {@link EnumerableHashJoin} based on its inputs and the join type. */ - public static List enumerableHashJoin(RelMetadataQuery mq, + public static @Nullable List enumerableHashJoin(RelMetadataQuery mq, RelNode left, RelNode right, JoinRelType joinType) { if (joinType == JoinRelType.SEMI) { return enumerableSemiJoin(mq, left, right); @@ -490,32 +499,32 @@ public static List enumerableHashJoin(RelMetadataQuery mq, * Returns the collation of {@link EnumerableNestedLoopJoin} * based on its inputs and the join type. */ - public static List enumerableNestedLoopJoin(RelMetadataQuery mq, + public static @Nullable List enumerableNestedLoopJoin(RelMetadataQuery mq, RelNode left, RelNode right, JoinRelType joinType) { return enumerableJoin0(mq, left, right, joinType); } - public static List enumerableCorrelate(RelMetadataQuery mq, + public static @Nullable List enumerableCorrelate(RelMetadataQuery mq, RelNode left, RelNode right, JoinRelType joinType) { // The current implementation always preserve the sort order of the left input return mq.collations(left); } - public static List enumerableSemiJoin(RelMetadataQuery mq, + public static @Nullable List enumerableSemiJoin(RelMetadataQuery mq, RelNode left, RelNode right) { // The current implementation always preserve the sort order of the left input return mq.collations(left); } @SuppressWarnings("unused") - public static List enumerableBatchNestedLoopJoin(RelMetadataQuery mq, + public static @Nullable List enumerableBatchNestedLoopJoin(RelMetadataQuery mq, RelNode left, RelNode right, JoinRelType joinType) { // The current implementation always preserve the sort order of the left input return mq.collations(left); } @SuppressWarnings("unused") - private static List enumerableJoin0(RelMetadataQuery mq, + private static @Nullable List enumerableJoin0(RelMetadataQuery mq, RelNode left, RelNode right, JoinRelType joinType) { // The current implementation can preserve the sort order of the left input if one of the // following conditions hold: diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java index cfb703c4a960..4be1e9eb4e0d 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java @@ -465,7 +465,7 @@ private boolean simplyProjects(RelNode rel, ImmutableBitSet columns) { private static ImmutableBitSet decorateWithConstantColumnsFromPredicates( ImmutableBitSet checkingColumns, RelNode rel, RelMetadataQuery mq) { final RelOptPredicateList predicates = mq.getPulledUpPredicates(rel); - if (predicates != null) { + if (!RelOptPredicateList.isEmpty(predicates)) { final Set constantIndexes = new HashSet<>(); predicates.constantMap.keySet().forEach(rex -> { if (rex instanceof RexInputRef) { diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java index da2a56c7bf51..12ff812ebb67 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java @@ -155,7 +155,7 @@ protected RelMdDistinctRowCount() {} groupKey, predicate, false); } - public Double getDistinctRowCount(Aggregate rel, RelMetadataQuery mq, + public @Nullable Double getDistinctRowCount(Aggregate rel, RelMetadataQuery mq, ImmutableBitSet groupKey, @Nullable RexNode predicate) { if (predicate == null || predicate.isAlwaysTrue()) { if (groupKey.isEmpty()) { diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistribution.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistribution.java index 82b5479ad7a3..b524efbb7632 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistribution.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistribution.java @@ -41,6 +41,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -90,7 +92,7 @@ public RelDistribution distribution(TableModify rel, RelMetadataQuery mq) { return mq.distribution(rel.getInput()); } - public RelDistribution distribution(TableScan scan, RelMetadataQuery mq) { + public @Nullable RelDistribution distribution(TableScan scan, RelMetadataQuery mq) { return table(scan.getTable()); } @@ -114,7 +116,7 @@ public RelDistribution distribution(HepRelVertex rel, RelMetadataQuery mq) { /** Helper method to determine a * {@link TableScan}'s distribution. */ - public static RelDistribution table(RelOptTable table) { + public static @Nullable RelDistribution table(RelOptTable table) { return table.getDistribution(); } diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExplainVisibility.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExplainVisibility.java index 6d73fad5165f..67955228a029 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExplainVisibility.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExplainVisibility.java @@ -20,6 +20,8 @@ import org.apache.calcite.sql.SqlExplainLevel; import org.apache.calcite.util.BuiltInMethod; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * RelMdExplainVisibility supplies a default implementation of * {@link RelMetadataQuery#isVisibleInExplain} for the standard logical algebra. @@ -47,7 +49,7 @@ private RelMdExplainVisibility() {} * * @see org.apache.calcite.rel.metadata.RelMetadataQuery#isVisibleInExplain(RelNode, SqlExplainLevel) */ - public Boolean isVisibleInExplain(RelNode rel, RelMetadataQuery mq, + public @Nullable Boolean isVisibleInExplain(RelNode rel, RelMetadataQuery mq, SqlExplainLevel explainLevel) { // no information available return null; diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExpressionLineage.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExpressionLineage.java index 4ecbdfa7a62a..78d437a799da 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExpressionLineage.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExpressionLineage.java @@ -62,6 +62,8 @@ import java.util.Set; import java.util.stream.Collectors; +import static java.util.Objects.requireNonNull; + /** * Default implementation of * {@link RelMetadataQuery#getExpressionLineage} for the standard logical @@ -485,7 +487,9 @@ private static class RexReplacer extends RexShuttle { } @Override public RexNode visitInputRef(RexInputRef inputRef) { - return replacementValues.get(inputRef); + return requireNonNull( + replacementValues.get(inputRef), + () -> "no replacement found for inputRef " + inputRef); } } diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdLowerBoundCost.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdLowerBoundCost.java index 2a18df5a5aab..97f632ad54c6 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdLowerBoundCost.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdLowerBoundCost.java @@ -23,6 +23,8 @@ import org.apache.calcite.rel.metadata.BuiltInMetadata.LowerBoundCost; import org.apache.calcite.util.BuiltInMethod; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Default implementations of the * {@link BuiltInMetadata.LowerBoundCost} @@ -44,7 +46,7 @@ protected RelMdLowerBoundCost() {} return BuiltInMetadata.LowerBoundCost.DEF; } - public RelOptCost getLowerBoundCost(RelSubset subset, + public @Nullable RelOptCost getLowerBoundCost(RelSubset subset, RelMetadataQuery mq, VolcanoPlanner planner) { if (planner.isLogical(subset)) { @@ -55,7 +57,7 @@ public RelOptCost getLowerBoundCost(RelSubset subset, return subset.getWinnerCost(); } - public RelOptCost getLowerBoundCost(RelNode node, + public @Nullable RelOptCost getLowerBoundCost(RelNode node, RelMetadataQuery mq, VolcanoPlanner planner) { if (planner.isLogical(node)) { // currently only support physical, will improve in the future diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMaxRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMaxRowCount.java index 1a4f9cec9ee1..31c632b5830c 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMaxRowCount.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMaxRowCount.java @@ -149,7 +149,7 @@ public Double getMaxRowCount(EnumerableLimit rel, RelMetadataQuery mq) { if (rel.getGroupType() == Aggregate.Group.SIMPLE) { final RelOptPredicateList predicateList = mq.getPulledUpPredicates(rel.getInput()); - if (predicateList != null + if (!RelOptPredicateList.isEmpty(predicateList) && allGroupKeysAreConstant(rel, predicateList)) { return 1D; } diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMemory.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMemory.java index 5d2d215767fe..a1019f0d2027 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMemory.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMemory.java @@ -19,6 +19,8 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.util.BuiltInMethod; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Default implementations of the * {@link org.apache.calcite.rel.metadata.BuiltInMetadata.Memory} @@ -52,7 +54,7 @@ protected RelMdMemory() {} * * @see org.apache.calcite.rel.metadata.RelMetadataQuery#memory */ - public Double memory(RelNode rel, RelMetadataQuery mq) { + public @Nullable Double memory(RelNode rel, RelMetadataQuery mq) { return null; } @@ -62,7 +64,7 @@ public Double memory(RelNode rel, RelMetadataQuery mq) { * * @see org.apache.calcite.rel.metadata.RelMetadataQuery#memory */ - public Double cumulativeMemoryWithinPhase(RelNode rel, RelMetadataQuery mq) { + public @Nullable Double cumulativeMemoryWithinPhase(RelNode rel, RelMetadataQuery mq) { Double nullable = mq.memory(rel); if (nullable == null) { return null; @@ -90,7 +92,7 @@ public Double cumulativeMemoryWithinPhase(RelNode rel, RelMetadataQuery mq) { * * @see org.apache.calcite.rel.metadata.RelMetadataQuery#cumulativeMemoryWithinPhaseSplit */ - public Double cumulativeMemoryWithinPhaseSplit(RelNode rel, + public @Nullable Double cumulativeMemoryWithinPhaseSplit(RelNode rel, RelMetadataQuery mq) { final Double memoryWithinPhase = mq.cumulativeMemoryWithinPhase(rel); final Integer splitCount = mq.splitCount(rel); diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java index f725293bbf61..ca39cc869765 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java @@ -30,6 +30,8 @@ import org.apache.calcite.util.BuiltInMethod; import org.apache.calcite.util.ImmutableBitSet; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -52,27 +54,27 @@ private RelMdPopulationSize() {} return BuiltInMetadata.PopulationSize.DEF; } - public Double getPopulationSize(Filter rel, RelMetadataQuery mq, + public @Nullable Double getPopulationSize(Filter rel, RelMetadataQuery mq, ImmutableBitSet groupKey) { return mq.getPopulationSize(rel.getInput(), groupKey); } - public Double getPopulationSize(Sort rel, RelMetadataQuery mq, + public @Nullable Double getPopulationSize(Sort rel, RelMetadataQuery mq, ImmutableBitSet groupKey) { return mq.getPopulationSize(rel.getInput(), groupKey); } - public Double getPopulationSize(Exchange rel, RelMetadataQuery mq, + public @Nullable Double getPopulationSize(Exchange rel, RelMetadataQuery mq, ImmutableBitSet groupKey) { return mq.getPopulationSize(rel.getInput(), groupKey); } - public Double getPopulationSize(TableModify rel, RelMetadataQuery mq, + public @Nullable Double getPopulationSize(TableModify rel, RelMetadataQuery mq, ImmutableBitSet groupKey) { return mq.getPopulationSize(rel.getInput(), groupKey); } - public Double getPopulationSize(Union rel, RelMetadataQuery mq, + public @Nullable Double getPopulationSize(Union rel, RelMetadataQuery mq, ImmutableBitSet groupKey) { double population = 0.0; for (RelNode input : rel.getInputs()) { @@ -85,12 +87,12 @@ public Double getPopulationSize(Union rel, RelMetadataQuery mq, return population; } - public Double getPopulationSize(Join rel, RelMetadataQuery mq, + public @Nullable Double getPopulationSize(Join rel, RelMetadataQuery mq, ImmutableBitSet groupKey) { return RelMdUtil.getJoinPopulationSize(mq, rel, groupKey); } - public Double getPopulationSize(Aggregate rel, RelMetadataQuery mq, + public @Nullable Double getPopulationSize(Aggregate rel, RelMetadataQuery mq, ImmutableBitSet groupKey) { ImmutableBitSet.Builder childKey = ImmutableBitSet.builder(); RelMdUtil.setAggChildKeys(groupKey, rel, childKey); @@ -103,7 +105,7 @@ public Double getPopulationSize(Values rel, RelMetadataQuery mq, return rel.estimateRowCount(mq) / 2; } - public Double getPopulationSize(Project rel, RelMetadataQuery mq, + public @Nullable Double getPopulationSize(Project rel, RelMetadataQuery mq, ImmutableBitSet groupKey) { ImmutableBitSet.Builder baseCols = ImmutableBitSet.builder(); ImmutableBitSet.Builder projCols = ImmutableBitSet.builder(); @@ -143,7 +145,7 @@ public Double getPopulationSize(Project rel, RelMetadataQuery mq, * * @see org.apache.calcite.rel.metadata.RelMetadataQuery#getPopulationSize(RelNode, ImmutableBitSet) */ - public Double getPopulationSize(RelNode rel, RelMetadataQuery mq, + public @Nullable Double getPopulationSize(RelNode rel, RelMetadataQuery mq, ImmutableBitSet groupKey) { // if the keys are unique, return the row count; otherwise, we have // no further information on which to return any legitimate value diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java index 769f124d638e..479fcb5494c4 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java @@ -64,6 +64,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; @@ -73,6 +75,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; import java.util.SortedMap; @@ -542,13 +545,13 @@ static class JoinConditionBasedPredicateInference { final Map exprFields; final Set allExprs; final Set equalityPredicates; - final RexNode leftChildPredicates; - final RexNode rightChildPredicates; + final @Nullable RexNode leftChildPredicates; + final @Nullable RexNode rightChildPredicates; final RexSimplify simplify; @SuppressWarnings("JdkObsolete") - JoinConditionBasedPredicateInference(Join joinRel, RexNode leftPredicates, - RexNode rightPredicates, RexSimplify simplify) { + JoinConditionBasedPredicateInference(Join joinRel, @Nullable RexNode leftPredicates, + @Nullable RexNode rightPredicates, RexSimplify simplify) { super(); this.joinRel = joinRel; this.simplify = simplify; @@ -711,11 +714,11 @@ public RelOptPredicateList inferPredicates( } } - public RexNode left() { + public @Nullable RexNode left() { return leftChildPredicates; } - public RexNode right() { + public @Nullable RexNode right() { return rightChildPredicates; } @@ -833,7 +836,7 @@ class ExprsItr implements Iterator { final int[] columns; final BitSet[] columnSets; final int[] iterationIdx; - Mapping nextMapping; + @Nullable Mapping nextMapping; boolean firstCall; @SuppressWarnings("JdkObsolete") @@ -862,6 +865,9 @@ class ExprsItr implements Iterator { } @Override public Mapping next() { + if (nextMapping == null) { + throw new NoSuchElementException(); + } return nextMapping; } diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java index 192cca054752..b9c4b8c083d7 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java @@ -35,6 +35,8 @@ import org.apache.calcite.util.BuiltInMethod; import org.apache.calcite.util.ImmutableBitSet; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.List; @@ -59,8 +61,8 @@ protected RelMdSelectivity() { return BuiltInMetadata.Selectivity.DEF; } - public Double getSelectivity(Union rel, RelMetadataQuery mq, - RexNode predicate) { + public @Nullable Double getSelectivity(Union rel, RelMetadataQuery mq, + @Nullable RexNode predicate) { if ((rel.getInputs().size() == 0) || (predicate == null)) { return 1.0; } @@ -95,18 +97,18 @@ public Double getSelectivity(Union rel, RelMetadataQuery mq, return sumSelectedRows / sumRows; } - public Double getSelectivity(Sort rel, RelMetadataQuery mq, - RexNode predicate) { + public @Nullable Double getSelectivity(Sort rel, RelMetadataQuery mq, + @Nullable RexNode predicate) { return mq.getSelectivity(rel.getInput(), predicate); } - public Double getSelectivity(TableModify rel, RelMetadataQuery mq, - RexNode predicate) { + public @Nullable Double getSelectivity(TableModify rel, RelMetadataQuery mq, + @Nullable RexNode predicate) { return mq.getSelectivity(rel.getInput(), predicate); } - public Double getSelectivity(Filter rel, RelMetadataQuery mq, - RexNode predicate) { + public @Nullable Double getSelectivity(Filter rel, RelMetadataQuery mq, + @Nullable RexNode predicate) { // Take the difference between the predicate passed in and the // predicate in the filter's condition, so we don't apply the // selectivity of the filter twice. If no predicate is passed in, @@ -122,7 +124,8 @@ public Double getSelectivity(Filter rel, RelMetadataQuery mq, } } - public Double getSelectivity(Calc rel, RelMetadataQuery mq, RexNode predicate) { + public @Nullable Double getSelectivity(Calc rel, RelMetadataQuery mq, + @Nullable RexNode predicate) { final RexProgram rexProgram = rel.getProgram(); final RexLocalRef programCondition = rexProgram.getCondition(); if (programCondition == null) { @@ -136,7 +139,8 @@ public Double getSelectivity(Calc rel, RelMetadataQuery mq, RexNode predicate) { } } - public Double getSelectivity(Join rel, RelMetadataQuery mq, RexNode predicate) { + public @Nullable Double getSelectivity(Join rel, RelMetadataQuery mq, + @Nullable RexNode predicate) { if (!rel.isSemiJoin()) { return getSelectivity((RelNode) rel, mq, predicate); } @@ -155,8 +159,8 @@ public Double getSelectivity(Join rel, RelMetadataQuery mq, RexNode predicate) { return mq.getSelectivity(rel.getLeft(), newPred); } - public Double getSelectivity(Aggregate rel, RelMetadataQuery mq, - RexNode predicate) { + public @Nullable Double getSelectivity(Aggregate rel, RelMetadataQuery mq, + @Nullable RexNode predicate) { final List notPushable = new ArrayList<>(); final List pushable = new ArrayList<>(); RelOptUtil.splitFilters( @@ -178,8 +182,8 @@ public Double getSelectivity(Aggregate rel, RelMetadataQuery mq, } } - public Double getSelectivity(Project rel, RelMetadataQuery mq, - RexNode predicate) { + public @Nullable Double getSelectivity(Project rel, RelMetadataQuery mq, + @Nullable RexNode predicate) { final List notPushable = new ArrayList<>(); final List pushable = new ArrayList<>(); RelOptUtil.splitFilters( @@ -209,7 +213,7 @@ public Double getSelectivity(Project rel, RelMetadataQuery mq, // Catch-all rule when none of the others apply. public Double getSelectivity(RelNode rel, RelMetadataQuery mq, - RexNode predicate) { + @Nullable RexNode predicate) { return RelMdUtil.guessSelectivity(predicate); } } 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 f922c8cc127c..f2c851c0808f 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 @@ -133,8 +133,7 @@ protected RelMdSize() {} public @Nullable List<@Nullable Double> averageColumnSizes(Project rel, RelMetadataQuery mq) { final List inputColumnSizes = mq.getAverageColumnSizesNotNull(rel.getInput()); - final ImmutableNullableList.Builder sizes = - ImmutableNullableList.builder(); + final ImmutableNullableList.Builder<@Nullable Double> sizes = ImmutableNullableList.builder(); for (RexNode project : rel.getProjects()) { sizes.add(averageRexSize(project, inputColumnSizes)); } @@ -144,8 +143,7 @@ protected RelMdSize() {} public @Nullable List<@Nullable Double> averageColumnSizes(Calc rel, RelMetadataQuery mq) { final List inputColumnSizes = mq.getAverageColumnSizesNotNull(rel.getInput()); - final ImmutableNullableList.Builder sizes = - ImmutableNullableList.builder(); + final ImmutableNullableList.Builder<@Nullable Double> sizes = ImmutableNullableList.builder(); rel.getProgram().split().left.forEach( exp -> sizes.add(averageRexSize(exp, inputColumnSizes))); return sizes.build(); @@ -153,28 +151,27 @@ protected RelMdSize() {} public @Nullable List<@Nullable Double> averageColumnSizes(Values rel, RelMetadataQuery mq) { final List fields = rel.getRowType().getFieldList(); - final ImmutableList.Builder list = ImmutableList.builder(); + final ImmutableNullableList.Builder<@Nullable Double> list = ImmutableNullableList.builder(); for (int i = 0; i < fields.size(); i++) { RelDataTypeField field = fields.get(i); - double d; if (rel.getTuples().isEmpty()) { - d = averageTypeValueSize(field.getType()); + list.add(averageTypeValueSize(field.getType())); } else { - d = 0; + double d = 0; for (ImmutableList literals : rel.getTuples()) { d += typeValueSize(field.getType(), literals.get(i).getValueAs(Comparable.class)); } d /= rel.getTuples().size(); + list.add(d); } - list.add(d); } return list.build(); } public List<@Nullable Double> averageColumnSizes(TableScan rel, RelMetadataQuery mq) { final List fields = rel.getRowType().getFieldList(); - final ImmutableList.Builder list = ImmutableList.builder(); + final ImmutableNullableList.Builder<@Nullable Double> list = ImmutableNullableList.builder(); for (RelDataTypeField field : fields) { list.add(averageTypeValueSize(field.getType())); } @@ -184,7 +181,7 @@ protected RelMdSize() {} public List<@Nullable Double> averageColumnSizes(Aggregate rel, RelMetadataQuery mq) { final List inputColumnSizes = mq.getAverageColumnSizesNotNull(rel.getInput()); - final ImmutableList.Builder list = ImmutableList.builder(); + final ImmutableNullableList.Builder<@Nullable Double> list = ImmutableNullableList.builder(); for (int key : rel.getGroupSet()) { list.add(inputColumnSizes.get(key)); } @@ -194,11 +191,11 @@ protected RelMdSize() {} return list.build(); } - public List<@Nullable Double> averageColumnSizes(Join rel, RelMetadataQuery mq) { + public @Nullable List<@Nullable Double> averageColumnSizes(Join rel, RelMetadataQuery mq) { return averageJoinColumnSizes(rel, mq); } - private @Nullable List averageJoinColumnSizes(Join rel, RelMetadataQuery mq) { + private @Nullable List<@Nullable Double> averageJoinColumnSizes(Join rel, RelMetadataQuery mq) { boolean semiOrAntijoin = !rel.getJoinType().projectsRight(); final RelNode left = rel.getLeft(); final RelNode right = rel.getRight(); @@ -232,9 +229,9 @@ protected RelMdSize() {} public @Nullable List<@Nullable Double> averageColumnSizes(Union rel, RelMetadataQuery mq) { final int fieldCount = rel.getRowType().getFieldCount(); - List> inputColumnSizeList = new ArrayList<>(); + List> inputColumnSizeList = new ArrayList<>(); for (RelNode input : rel.getInputs()) { - final List inputSizes = mq.getAverageColumnSizes(input); + final List<@Nullable Double> inputSizes = mq.getAverageColumnSizes(input); if (inputSizes != null) { inputColumnSizeList.add(inputSizes); } @@ -329,7 +326,10 @@ protected RelMdSize() {} case ROW: double average = 0.0; for (RelDataTypeField field : type.getFieldList()) { - average += averageTypeValueSize(field.getType()); + Double size = averageTypeValueSize(field.getType()); + if (size != null) { + average += size; + } } return average; default: @@ -341,7 +341,7 @@ protected RelMdSize() {} * *

Nulls count as 1 byte. */ - public double typeValueSize(RelDataType type, Comparable value) { + public double typeValueSize(RelDataType type, @Nullable Comparable value) { if (value == null) { return 1d; } @@ -387,7 +387,7 @@ public double typeValueSize(RelDataType type, Comparable value) { } } - public Double averageRexSize(RexNode node, List inputColumnSizes) { + public @Nullable Double averageRexSize(RexNode node, List inputColumnSizes) { switch (node.getKind()) { case INPUT_REF: return inputColumnSizes.get(((RexInputRef) node).getIndex()); diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java index a3b3c0b6daad..f922715ae128 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java @@ -368,7 +368,7 @@ public static double capInfinity(Double d) { * means true, so gives selectity of 1.0 * @return estimated selectivity */ - public static double guessSelectivity(RexNode predicate) { + public static double guessSelectivity(@Nullable RexNode predicate) { return guessSelectivity(predicate, false); } diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataProvider.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataProvider.java index b780b24963da..1bd9a20bfeec 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataProvider.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataProvider.java @@ -64,7 +64,7 @@ public interface RelMetadataProvider { * @return Function that will field a metadata instance; or null if this * provider cannot supply metadata of this type */ - @Nullable UnboundMetadata apply( + <@Nullable M extends @Nullable Metadata> @Nullable UnboundMetadata apply( Class relClass, Class metadataClass); Multimap> handlers( 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 c4feac775b81..4abda11a2475 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 @@ -425,7 +425,7 @@ public static RelMetadataQuery instance() { * @return estimated selectivity (between 0.0 and 1.0), or null if no * reliable estimate can be determined */ - public @Nullable Double getSelectivity(RelNode rel, RexNode predicate) { + public @Nullable Double getSelectivity(RelNode rel, @Nullable RexNode predicate) { for (;;) { try { Double result = selectivityHandler.getSelectivity(rel, this, predicate); @@ -786,10 +786,11 @@ public RelDistribution distribution(RelNode rel) { * @param rel the relational expression * @return Predicates that can be pulled above this RelNode */ - public @Nullable RelOptPredicateList getPulledUpPredicates(RelNode rel) { + public RelOptPredicateList getPulledUpPredicates(RelNode rel) { for (;;) { try { - return predicatesHandler.getPredicates(rel, this); + RelOptPredicateList result = predicatesHandler.getPredicates(rel, this); + return result != null ? result : RelOptPredicateList.EMPTY; } catch (JaninoRelMetadataProvider.NoHandler e) { predicatesHandler = revise(e.relClass, BuiltInMetadata.Predicates.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 6138dcd00a2e..ae4da35cfc33 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 @@ -122,6 +122,7 @@ public class RelToSqlConverter extends SqlImplementor private final Deque stack = new ArrayDeque<>(); /** Creates a RelToSqlConverter. */ + @SuppressWarnings("argument.type.incompatible") public RelToSqlConverter(SqlDialect dialect) { super(dialect); dispatcher = ReflectUtil.createMethodDispatcher(Result.class, this, "visit", @@ -150,7 +151,7 @@ protected Result dispatch(RelNode e) { } @Override protected Result result(SqlNode node, Collection clauses, - String neededAlias, RelDataType neededType, + @Nullable String neededAlias, @Nullable RelDataType neededType, Map aliases) { final Frame frame = Objects.requireNonNull(stack.peek()); return super.result(node, clauses, neededAlias, neededType, aliases) 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 b629040fa266..1df4d175cbbd 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 @@ -1313,7 +1313,8 @@ public static SqlNode toSql(@Nullable RexProgram program, RexLiteral literal) { /** Converts a {@link RexLiteral} to a {@link SqlLiteral}. */ public static SqlNode toSql(RexLiteral literal) { - switch (literal.getTypeName()) { + SqlTypeName typeName = literal.getTypeName(); + switch (typeName) { case SYMBOL: final Enum symbol = (Enum) literal.getValue(); return SqlLiteral.createSymbol(symbol, POS); @@ -1332,7 +1333,9 @@ public static SqlNode toSql(RexLiteral literal) { default: break; } - switch (literal.getTypeName().getFamily()) { + SqlTypeFamily family = requireNonNull(typeName.getFamily(), + () -> "literal " + literal + " has null SqlTypeFamily, and is SqlTypeName is " + typeName); + switch (family) { case CHARACTER: return SqlLiteral.createCharString((String) castNonNull(literal.getValue2()), POS); case NUMERIC: @@ -1363,7 +1366,7 @@ public static SqlNode toSql(RexLiteral literal) { literal.getType().getPrecision(), POS); case ANY: case NULL: - switch (literal.getTypeName()) { + switch (typeName) { case NULL: return SqlLiteral.createNull(POS); default: @@ -1371,7 +1374,7 @@ public static SqlNode toSql(RexLiteral literal) { } // fall through default: - throw new AssertionError(literal + ": " + literal.getTypeName()); + throw new AssertionError(literal + ": " + typeName); } } @@ -1792,7 +1795,7 @@ public SqlNode asFrom() { SqlCall sqlCall = (SqlCall) node; @SuppressWarnings({"assignment.type.incompatible", "toArray.nullable.elements.not.newarray"}) - SqlNode[] operands = sqlCall.getOperandList().toArray(SqlNode.EMPTY_ARRAY); + SqlNode[] operands = sqlCall.getOperandList().toArray(new SqlNode[0]); operands[1] = new SqlIdentifier(neededAlias, POS); return SqlStdOperatorTable.AS.createCall(POS, operands); } else { diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java index b044c6dbc928..7460d8505952 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java @@ -94,7 +94,7 @@ public AggregateProjectPullUpConstantsRule( final RelMetadataQuery mq = call.getMetadataQuery(); final RelOptPredicateList predicates = mq.getPulledUpPredicates(aggregate.getInput()); - if (predicates == null) { + if (RelOptPredicateList.isEmpty(predicates)) { return; } final NavigableMap map = new TreeMap<>(); diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java index d7ee66cc38ed..058e23df2e75 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java @@ -47,6 +47,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.List; @@ -186,7 +188,7 @@ protected void apply(RelOptRuleCall call, Project postProject, call.transformTo(relBuilder.build()); } - private static AggregateCall rollUp(int groupCount, RelBuilder relBuilder, + private static @Nullable AggregateCall rollUp(int groupCount, RelBuilder relBuilder, AggregateCall aggregateCall, TileKey tileKey) { if (aggregateCall.isDistinct()) { return null; diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ExchangeRemoveConstantKeysRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ExchangeRemoveConstantKeysRule.java index 096162f787ee..f09c5c117a42 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/ExchangeRemoveConstantKeysRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/ExchangeRemoveConstantKeysRule.java @@ -80,7 +80,7 @@ private static void matchExchange(ExchangeRemoveConstantKeysRule rule, final RelMetadataQuery mq = call.getMetadataQuery(); final RelNode input = exchange.getInput(); final RelOptPredicateList predicates = mq.getPulledUpPredicates(input); - if (predicates == null) { + if (RelOptPredicateList.isEmpty(predicates)) { return; } @@ -115,7 +115,7 @@ private static void matchSortExchange(ExchangeRemoveConstantKeysRule rule, final RelMetadataQuery mq = call.getMetadataQuery(); final RelNode input = sortExchange.getInput(); final RelOptPredicateList predicates = mq.getPulledUpPredicates(input); - if (predicates == null) { + if (RelOptPredicateList.isEmpty(predicates)) { return; } diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java index a0d39b3b86fb..51e5b190eca0 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java @@ -164,7 +164,7 @@ public JoinToMultiJoinRule(Class joinClass, // pull up the join filters from the children MultiJoinRels and // combine them with the join filter associated with this LogicalJoin to // form the join filter for the new MultiJoin - List newJoinFilters = combineJoinFilters(origJoin, left, right); + List<@Nullable RexNode> newJoinFilters = combineJoinFilters(origJoin, left, right); // add on the join field reference counts for the join condition // associated with this LogicalJoin @@ -174,7 +174,7 @@ public JoinToMultiJoinRule(Class joinClass, origJoin.getCondition(), joinFieldRefCountsList); - List newPostJoinFilters = + List<@Nullable RexNode> newPostJoinFilters = combinePostJoinFilters(origJoin, left, right); final RexBuilder rexBuilder = origJoin.getCluster().getRexBuilder(); @@ -387,7 +387,7 @@ private void copyOuterJoinInfo( * @param right Right input of the join * @return combined join filters AND-ed together */ - private List combineJoinFilters( + private List<@Nullable RexNode> combineJoinFilters( Join join, RelNode left, RelNode right) { @@ -396,7 +396,7 @@ private List combineJoinFilters( // AND the join condition if this isn't a left or right outer join; // in those cases, the outer join condition is already tracked // separately - final List filters = new ArrayList<>(); + final List<@Nullable RexNode> filters = new ArrayList<>(); if ((joinType != JoinRelType.LEFT) && (joinType != JoinRelType.RIGHT)) { filters.add(join.getCondition()); } @@ -441,11 +441,11 @@ private boolean canCombine(RelNode input, boolean nullGenerating) { * @param rightFilter the filter originating from the right child * @return the adjusted right filter */ - private RexNode shiftRightFilter( + private @Nullable RexNode shiftRightFilter( Join joinRel, RelNode left, MultiJoin right, - RexNode rightFilter) { + @Nullable RexNode rightFilter) { if (rightFilter == null) { return null; } @@ -534,11 +534,11 @@ private ImmutableMap addOnJoinFieldRefCounts( * @param right right child of the LogicalJoin * @return combined post-join filters AND'd together */ - private List combinePostJoinFilters( + private List<@Nullable RexNode> combinePostJoinFilters( Join joinRel, RelNode left, RelNode right) { - final List filters = new ArrayList<>(); + final List<@Nullable RexNode> filters = new ArrayList<>(); if (right instanceof MultiJoin) { final MultiJoin multiRight = (MultiJoin) right; filters.add( diff --git a/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java b/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java index f81b03ffdcb1..4bc89c606b60 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java @@ -46,6 +46,8 @@ import java.util.Map; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** * Utility class that keeps track of the join factors that * make up a {@link MultiJoin}. @@ -111,13 +113,13 @@ public class LoptMultiJoin { * For each join filter, associates a bitmap indicating all factors * referenced by the filter. */ - private Map factorsRefByJoinFilter; + private @Nullable Map factorsRefByJoinFilter; /** * For each join filter, associates a bitmap indicating all fields * referenced by the filter. */ - private Map fieldsRefByJoinFilter; + private @Nullable Map fieldsRefByJoinFilter; /** * Starting RexInputRef index corresponding to each join factor. @@ -133,12 +135,12 @@ public class LoptMultiJoin { * Bitmap indicating which factors each factor references in join filters * that correspond to comparisons. */ - ImmutableBitSet [] factorsRefByFactor; + ImmutableBitSet @Nullable [] factorsRefByFactor; /** * Weights of each factor combination. */ - int [][] factorWeights; + int @Nullable [][] factorWeights; /** * Type factory. @@ -288,7 +290,11 @@ public List getJoinFilters() { * @param joinFilter Filter for which information will be returned */ public ImmutableBitSet getFactorsRefByJoinFilter(RexNode joinFilter) { - return factorsRefByJoinFilter.get(joinFilter); + Map factorsRefByJoinFilter = + requireNonNull(this.factorsRefByJoinFilter, "fieldsRefByJoinFilter"); + return requireNonNull( + factorsRefByJoinFilter.get(joinFilter), + () -> "joinFilter is not found in factorsRefByJoinFilter: " + joinFilter); } /** @@ -304,13 +310,17 @@ public List getMultiJoinFields() { * @param joinFilter the filter for which information will be returned */ public ImmutableBitSet getFieldsRefByJoinFilter(RexNode joinFilter) { - return fieldsRefByJoinFilter.get(joinFilter); + Map fieldsRefByJoinFilter = + requireNonNull(this.fieldsRefByJoinFilter, "fieldsRefByJoinFilter"); + return requireNonNull( + fieldsRefByJoinFilter.get(joinFilter), + () -> "joinFilter is not found in fieldsRefByJoinFilter: " + joinFilter); } /** * Returns weights of the different factors relative to one another. */ - public int [][] getFactorWeights() { + public int @Nullable [][] getFactorWeights() { return factorWeights; } @@ -321,7 +331,7 @@ public ImmutableBitSet getFieldsRefByJoinFilter(RexNode joinFilter) { * @param factIdx Factor for which information will be returned */ public ImmutableBitSet getFactorsRefByFactor(int factIdx) { - return factorsRefByFactor[factIdx]; + return requireNonNull(factorsRefByFactor, "factorsRefByFactor")[factIdx]; } /** @@ -360,7 +370,7 @@ public ImmutableBitSet getOuterJoinFactors(int factIdx) { * * @param factIdx Factor for which information will be returned */ - public RexNode getOuterJoinCond(int factIdx) { + public @Nullable RexNode getOuterJoinCond(int factIdx) { return multiJoin.getOuterJoinConditions().get(factIdx); } @@ -379,7 +389,9 @@ public ImmutableBitSet getProjFields(int factIdx) { * @param factIdx Factor for which information will be returned */ public int [] getJoinFieldRefCounts(int factIdx) { - return joinFieldRefCountsMap.get(factIdx); + return requireNonNull( + joinFieldRefCountsMap.get(factIdx), + () -> "no entry in joinFieldRefCountsMap found for " + factIdx); } /** @@ -439,7 +451,8 @@ ImmutableBitSet getJoinFilterFactorBitmap( boolean setFields) { ImmutableBitSet fieldRefBitmap = fieldBitmap(joinFilter); if (setFields) { - fieldsRefByJoinFilter.put(joinFilter, fieldRefBitmap); + requireNonNull(fieldsRefByJoinFilter, "fieldsRefByJoinFilter") + .put(joinFilter, fieldRefBitmap); } return factorBitmap(fieldRefBitmap); @@ -521,7 +534,8 @@ public void setFactorWeights() { } for (RexNode joinFilter : allJoinFilters) { - ImmutableBitSet factorRefs = factorsRefByJoinFilter.get(joinFilter); + ImmutableBitSet factorRefs = requireNonNull(factorsRefByJoinFilter, "factorsRefByJoinFilter") + .get(joinFilter); // don't give weights to non-comparison expressions if (!(joinFilter instanceof RexCall)) { @@ -592,7 +606,7 @@ public void setFactorWeights() { * @param rightFactor index of right factor */ private void setFactorWeight(int weight, int leftFactor, int rightFactor) { - if (factorWeights[leftFactor][rightFactor] < weight) { + if (requireNonNull(factorWeights, "factorWeights")[leftFactor][rightFactor] < weight) { factorWeights[leftFactor][rightFactor] = weight; factorWeights[rightFactor][leftFactor] = weight; } diff --git a/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java b/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java index 6517586c65dc..249cfc077393 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java @@ -42,6 +42,8 @@ import com.google.common.collect.Lists; import com.google.common.collect.Ordering; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; @@ -236,7 +238,7 @@ private int isSuitableFilter( * @return SemiJoin containing information regarding the semijoin that * can be used to filter the fact table */ - private LogicalJoin findSemiJoinIndexByCost( + private @Nullable LogicalJoin findSemiJoinIndexByCost( LoptMultiJoin multiJoin, List joinFilters, int factIdx, @@ -399,7 +401,7 @@ private RexNode adjustSemiJoinCondition( * @return the underlying fact table if the semijoin keys are valid; * otherwise null */ - private LcsTable validateKeys( + private @Nullable LcsTable validateKeys( RelNode factRel, List leftKeys, List rightKeys, @@ -464,7 +466,7 @@ private LcsTable validateKeys( * @return modified expression with filters that don't reference specified * keys removed */ - private RexNode removeExtraFilters( + private @Nullable RexNode removeExtraFilters( List keys, int nFields, RexNode condition) { @@ -829,7 +831,7 @@ private static class LcsTableScan { private static class LcsIndexOptimizer { LcsIndexOptimizer(LcsTableScan rel) {} - public FemLocalIndex findSemiJoinIndexByCost(RelNode dimRel, + public @Nullable FemLocalIndex findSemiJoinIndexByCost(RelNode dimRel, List actualLeftKeys, List rightKeys, List bestKeyOrder) { return null; diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceDecimalsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceDecimalsRule.java index 2dac2db49f93..f4b98927156c 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceDecimalsRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceDecimalsRule.java @@ -179,7 +179,7 @@ private void register(RexNode node, RexNode reducedNode) { /** * Looks up a registered node. */ - private RexNode lookup(RexNode node) { + private @Nullable RexNode lookup(RexNode node) { Pair key = RexUtil.makeKey(node); if (irreducible.get(key) != null) { return node; diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java index c53275c68ce2..bbdb0a9c5a7d 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java @@ -71,6 +71,8 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; @@ -929,7 +931,7 @@ protected static class RexReplacer extends RexShuttle { return node; } - private RexNode visit(final RexNode call) { + private @Nullable RexNode visit(final RexNode call) { int i = reducibleExps.indexOf(call); if (i == -1) { return null; diff --git a/core/src/main/java/org/apache/calcite/rel/rules/SortRemoveConstantKeysRule.java b/core/src/main/java/org/apache/calcite/rel/rules/SortRemoveConstantKeysRule.java index 65f727ab0a38..6555b254d4c9 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/SortRemoveConstantKeysRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/SortRemoveConstantKeysRule.java @@ -51,7 +51,7 @@ protected SortRemoveConstantKeysRule(Config config) { final RelMetadataQuery mq = call.getMetadataQuery(); final RelNode input = sort.getInput(); final RelOptPredicateList predicates = mq.getPulledUpPredicates(input); - if (predicates == null) { + if (RelOptPredicateList.isEmpty(predicates)) { return; } diff --git a/core/src/main/java/org/apache/calcite/rel/rules/UnionPullUpConstantsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/UnionPullUpConstantsRule.java index 5f89ed0f1e49..6528ac3be3d6 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/UnionPullUpConstantsRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/UnionPullUpConstantsRule.java @@ -67,7 +67,7 @@ public UnionPullUpConstantsRule(Class unionClass, final RexBuilder rexBuilder = union.getCluster().getRexBuilder(); final RelMetadataQuery mq = call.getMetadataQuery(); final RelOptPredicateList predicates = mq.getPulledUpPredicates(union); - if (predicates == null) { + if (RelOptPredicateList.isEmpty(predicates)) { return; } diff --git a/core/src/main/java/org/apache/calcite/rel/rules/materialize/MaterializedViewAggregateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/materialize/MaterializedViewAggregateRule.java index ba933f9a7a7a..3375518c83d3 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/materialize/MaterializedViewAggregateRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/materialize/MaterializedViewAggregateRule.java @@ -78,6 +78,8 @@ import java.util.Map; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** Materialized view rewriting for aggregate. * * @param Configuration type @@ -902,7 +904,7 @@ protected SqlFunction getFloorSqlFunction(TimeUnitRange flag) { topNode = topNode.getInput(0); } } - return Pair.of(resultTopViewProject, resultViewNode); + return Pair.of(resultTopViewProject, requireNonNull(resultViewNode, "resultViewNode")); } /** Rule configuration. */ diff --git a/core/src/main/java/org/apache/calcite/rel/type/DynamicRecordTypeImpl.java b/core/src/main/java/org/apache/calcite/rel/type/DynamicRecordTypeImpl.java index fdde69b7fe4c..22084195b4ac 100644 --- a/core/src/main/java/org/apache/calcite/rel/type/DynamicRecordTypeImpl.java +++ b/core/src/main/java/org/apache/calcite/rel/type/DynamicRecordTypeImpl.java @@ -17,6 +17,7 @@ package org.apache.calcite.rel.type; import org.apache.calcite.sql.type.SqlTypeExplicitPrecedenceList; +import org.apache.calcite.sql.type.SqlTypeFamily; import org.apache.calcite.sql.type.SqlTypeName; import org.apache.calcite.util.Pair; @@ -85,7 +86,8 @@ public DynamicRecordTypeImpl(RelDataTypeFactory typeFactory) { } @Override public RelDataTypeFamily getFamily() { - return getSqlTypeName().getFamily(); + SqlTypeFamily family = getSqlTypeName().getFamily(); + return family != null ? family : this; } } diff --git a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java index 4454285e236f..7904ab712804 100644 --- a/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java +++ b/core/src/main/java/org/apache/calcite/rel/type/RelDataTypeFactoryImpl.java @@ -243,18 +243,16 @@ private RelDataType createStructType( // REVIEW jvs 22-Jan-2004: Always use the field name from the // first type? final int k = j; + + RelDataType type = leastRestrictive( + Util.transform(types, t -> t.getFieldList().get(k).getType()) + ); + if (type == null) { + return null; + } builder.add( type0.getFieldList().get(j).getName(), - leastRestrictive( - new AbstractList() { - @Override public RelDataType get(int index) { - return types.get(index).getFieldList().get(k).getType(); - } - - @Override public int size() { - return types.size(); - } - })); + type); } return createTypeWithNullability(builder.build(), isNullable); } @@ -438,7 +436,7 @@ public static boolean isJavaType(RelDataType t) { return t instanceof JavaType; } - private List fieldsOf(Class clazz) { + private @Nullable List fieldsOf(Class clazz) { final List list = new ArrayList<>(); for (Field field : clazz.getFields()) { if (Modifier.isStatic(field.getModifiers())) { @@ -565,6 +563,7 @@ public JavaType( this(clazz, nullable, null, null); } + @SuppressWarnings("argument.type.incompatible") public JavaType( Class clazz, boolean nullable, 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 64df5fae16bd..f5c85fc9e9e1 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,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; -import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.initialization.qual.UnknownInitialization; import org.checkerframework.checker.nullness.qual.Nullable; import java.io.Serializable; @@ -184,7 +184,6 @@ private static void getFieldRecurse(List slots, RelDataType type, return null; } - @EnsuresNonNullIf(expression = "fieldList", result = true) @Override public boolean isStruct() { return fieldList != null; } @@ -200,7 +199,7 @@ private static void getFieldRecurse(List slots, RelDataType type, } @Override public String getFullTypeString() { - return digest; + return requireNonNull(digest, "digest"); } @Override public boolean isNullable() { @@ -269,7 +268,10 @@ protected abstract void generateTypeString( * Computes the digest field. This should be called in every non-abstract * subclass constructor once the type is fully defined. */ - protected void computeDigest() { + @SuppressWarnings("method.invocation.invalid") + protected void computeDigest( + @UnknownInitialization RelDataTypeImpl this + ) { StringBuilder sb = new StringBuilder(); generateTypeString(sb, true); if (!isNullable()) { diff --git a/core/src/main/java/org/apache/calcite/rex/LogicVisitor.java b/core/src/main/java/org/apache/calcite/rex/LogicVisitor.java index 881994a160a1..74de8d7e7400 100644 --- a/core/src/main/java/org/apache/calcite/rex/LogicVisitor.java +++ b/core/src/main/java/org/apache/calcite/rex/LogicVisitor.java @@ -20,6 +20,8 @@ import com.google.common.collect.Iterables; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Collection; import java.util.Collections; import java.util.EnumSet; @@ -29,7 +31,7 @@ /** * Visitor pattern for traversing a tree of {@link RexNode} objects. */ -public class LogicVisitor extends RexUnaryBiVisitor { +public class LogicVisitor extends RexUnaryBiVisitor<@Nullable Logic> { private final RexNode seek; private final Collection logicCollection; 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 c137d1d7a717..6fe22c6cfbc6 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java +++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java @@ -141,7 +141,7 @@ public RexBuilder(RelDataTypeFactory typeFactory) { /** Creates a list of {@link org.apache.calcite.rex.RexInputRef} expressions, * projecting the fields of a given record type. */ - public List identityProjects(final RelDataType rowType) { + public List identityProjects(final RelDataType rowType) { return Util.transform(rowType.getFieldList(), input -> new RexInputRef(input.getIndex(), input.getType())); } diff --git a/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java b/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java index 6565aca02e50..1e3ccdf91078 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java +++ b/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java @@ -85,7 +85,7 @@ public static RexCallBinding create(RelDataTypeFactory typeFactory, return RexLiteral.intValue(operands.get(ordinal)); } - @Override public T getOperandLiteralValue(int ordinal, Class clazz) { + @Override public @Nullable T getOperandLiteralValue(int ordinal, Class clazz) { final RexNode node = operands.get(ordinal); if (node instanceof RexLiteral) { return ((RexLiteral) node).getValueAs(clazz); diff --git a/core/src/main/java/org/apache/calcite/rex/RexChecker.java b/core/src/main/java/org/apache/calcite/rex/RexChecker.java index 30f7a876154d..af6e4adc2f71 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexChecker.java +++ b/core/src/main/java/org/apache/calcite/rex/RexChecker.java @@ -26,6 +26,8 @@ import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Visitor which checks the validity of a {@link RexNode} expression. * @@ -56,7 +58,7 @@ * * @see RexNode */ -public class RexChecker extends RexVisitorImpl { +public class RexChecker extends RexVisitorImpl<@Nullable Boolean> { //~ Instance fields -------------------------------------------------------- protected final RelNode.@Nullable Context context; @@ -183,6 +185,7 @@ public int getFailureCount() { * Returns whether an expression is valid. */ public final boolean isValid(RexNode expr) { - return expr.accept(this); + return requireNonNull(expr.accept(this), + () -> "expr.accept(RexChecker) for expr=" + expr); } } diff --git a/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java b/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java index 605c019771b2..060495478496 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java +++ b/core/src/main/java/org/apache/calcite/rex/RexExecutorImpl.java @@ -39,6 +39,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.List; @@ -151,7 +153,7 @@ private static class DataContextInputGetter implements InputGetter { this.typeFactory = typeFactory; } - @Override public Expression field(BlockBuilder list, int index, Type storageType) { + @Override public Expression field(BlockBuilder list, int index, @Nullable Type storageType) { MethodCallExpression recFromCtx = Expressions.call( DataContext.ROOT, BuiltInMethod.DATA_CONTEXT_GET.method, 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 134ec920dc23..ebe119b7c471 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java +++ b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java @@ -793,7 +793,7 @@ private static RexLiteral toLiteral(RelDataType type, Comparable value) { collation); return new RexLiteral(str, type, typeName); case BOOLEAN: - boolean b = ConversionUtil.toBoolean(literal); + Boolean b = ConversionUtil.toBoolean(literal); return new RexLiteral(b, type, typeName); case DECIMAL: case DOUBLE: diff --git a/core/src/main/java/org/apache/calcite/rex/RexNormalize.java b/core/src/main/java/org/apache/calcite/rex/RexNormalize.java index fb7af07baf7b..c5b9cf9f4ff9 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexNormalize.java +++ b/core/src/main/java/org/apache/calcite/rex/RexNormalize.java @@ -175,7 +175,7 @@ private static int unorderedHash(List xs) { int b = 0; int c = 1; for (Object x : xs) { - int h = x.hashCode(); + int h = Objects.hashCode(x); a += h; b ^= h; if (h != 0) { 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 549a1191b467..bd0b5118c2f7 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexProgram.java +++ b/core/src/main/java/org/apache/calcite/rex/RexProgram.java @@ -245,8 +245,10 @@ public static RexProgram create( * In this case, the input is mainly from the output json string of {@link RelJsonWriter} */ public static RexProgram create(RelInput input) { - final List exprs = input.getExpressionList("exprs"); - final List projectRexNodes = input.getExpressionList("projects"); + final List exprs = requireNonNull(input.getExpressionList("exprs"), "exprs"); + final List projectRexNodes = requireNonNull( + input.getExpressionList("projects"), + "projects"); final List projects = new ArrayList<>(projectRexNodes.size()); for (RexNode rexNode: projectRexNodes) { projects.add((RexLocalRef) rexNode); 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 26e0ce3846fc..06aee7ce13c3 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexProgramBuilder.java +++ b/core/src/main/java/org/apache/calcite/rex/RexProgramBuilder.java @@ -67,6 +67,7 @@ public RexProgramBuilder(RelDataType inputRowType, RexBuilder rexBuilder) { /** * Creates a program-builder. */ + @SuppressWarnings("method.invocation.invalid") private RexProgramBuilder(RelDataType inputRowType, RexBuilder rexBuilder, @Nullable RexSimplify simplify) { this.inputRowType = Objects.requireNonNull(inputRowType); @@ -95,6 +96,7 @@ private RexProgramBuilder(RelDataType inputRowType, RexBuilder rexBuilder, * @param normalize Whether to normalize * @param simplify Simplifier, or null to not simplify */ + @SuppressWarnings("method.invocation.invalid") private RexProgramBuilder( RexBuilder rexBuilder, final RelDataType inputRowType, @@ -269,14 +271,15 @@ public RexLocalRef addProject(int at, int ordinal, final String name) { */ public void addCondition(RexNode expr) { assert expr != null; + RexLocalRef conditionRef = this.conditionRef; if (conditionRef == null) { - conditionRef = registerInput(expr); + this.conditionRef = conditionRef = registerInput(expr); } else { // AND the new condition with the existing condition. // If the new condition is identical to the existing condition, skip it. RexLocalRef ref = registerInput(expr); if (!ref.equals(conditionRef)) { - conditionRef = + this.conditionRef = registerInput( rexBuilder.makeCall( SqlStdOperatorTable.AND, diff --git a/core/src/main/java/org/apache/calcite/rex/RexSqlReflectiveConvertletTable.java b/core/src/main/java/org/apache/calcite/rex/RexSqlReflectiveConvertletTable.java index 1bf6aaab5d43..fdaf3eb83dce 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexSqlReflectiveConvertletTable.java +++ b/core/src/main/java/org/apache/calcite/rex/RexSqlReflectiveConvertletTable.java @@ -51,7 +51,7 @@ public RexSqlReflectiveConvertletTable() { // Is there a convertlet for this class of operator // (e.g. SqlBinaryOperator)? - Class clazz = op.getClass(); + @Nullable Class clazz = op.getClass(); while (clazz != null) { convertlet = (RexSqlConvertlet) map.get(clazz); if (convertlet != null) { diff --git a/core/src/main/java/org/apache/calcite/rex/RexSqlStandardConvertletTable.java b/core/src/main/java/org/apache/calcite/rex/RexSqlStandardConvertletTable.java index 1bc982f8de6c..fad0578367dc 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexSqlStandardConvertletTable.java +++ b/core/src/main/java/org/apache/calcite/rex/RexSqlStandardConvertletTable.java @@ -169,10 +169,11 @@ public RexSqlStandardConvertletTable() { final SqlNode[] exprs = new SqlNode[nodes.size()]; for (int i = 0; i < nodes.size(); i++) { RexNode node = nodes.get(i); - exprs[i] = converter.convertNode(node); - if (exprs[i] == null) { + SqlNode converted = converter.convertNode(node); + if (converted == null) { return null; } + exprs[i] = converted; } return exprs; } diff --git a/core/src/main/java/org/apache/calcite/rex/RexUnaryBiVisitor.java b/core/src/main/java/org/apache/calcite/rex/RexUnaryBiVisitor.java index 57007e4d4766..7f4ca0ea6623 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexUnaryBiVisitor.java +++ b/core/src/main/java/org/apache/calcite/rex/RexUnaryBiVisitor.java @@ -16,13 +16,15 @@ */ package org.apache.calcite.rex; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Default implementation of a {@link RexBiVisitor} whose payload and return * type are the same. * * @param Return type from each {@code visitXxx} method */ -public class RexUnaryBiVisitor extends RexBiVisitorImpl { +public class RexUnaryBiVisitor<@Nullable R> extends RexBiVisitorImpl { /** Creates a RexUnaryBiVisitor. */ protected RexUnaryBiVisitor(boolean deep) { super(deep); 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 59fc94ed976f..3e4a991501ce 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java +++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java @@ -70,6 +70,8 @@ import static org.apache.calcite.linq4j.Nullness.castNonNull; +import static java.util.Objects.requireNonNull; + /** * Utility methods concerning row-expressions. */ @@ -469,8 +471,11 @@ private static boolean canAssignFrom(RelDataType type1, RelDataType type2, RelDataTypeFactory typeFactory) { final SqlTypeName name1 = type1.getSqlTypeName(); final SqlTypeName name2 = type2.getSqlTypeName(); - if (name1.getFamily() == name2.getFamily()) { - switch (name1.getFamily()) { + final RelDataType type1Final = type1; + SqlTypeFamily family = requireNonNull(name1.getFamily(), + () -> "SqlTypeFamily is null for type " + type1Final + ", SqlTypeName " + name1); + if (family == name2.getFamily()) { + switch (family) { case NUMERIC: if (SqlTypeUtil.isExactNumeric(type1) && SqlTypeUtil.isExactNumeric(type2)) { @@ -618,9 +623,10 @@ public static RexNode expandSearch(RexBuilder rexBuilder, return composeDisjunction(rexBuilder, orList); } - private static RexNode deref(RexProgram program, RexNode node) { + private static RexNode deref(@Nullable RexProgram program, RexNode node) { while (node instanceof RexLocalRef) { - node = program.getExprList().get(((RexLocalRef) node).index); + node = requireNonNull(program, "program") + .getExprList().get(((RexLocalRef) node).index); } return node; } @@ -1186,9 +1192,9 @@ public static boolean isIdentity(List exps, /** As {@link #composeConjunction(RexBuilder, Iterable, boolean)} but never * returns null. */ public static RexNode composeConjunction(RexBuilder rexBuilder, - Iterable nodes) { + Iterable nodes) { final RexNode e = composeConjunction(rexBuilder, nodes, false); - return Objects.requireNonNull(e); + return requireNonNull(e); } /** @@ -1262,7 +1268,7 @@ private static void addAnd(ImmutableList.Builder builder, public static RexNode composeDisjunction(RexBuilder rexBuilder, Iterable nodes) { final RexNode e = composeDisjunction(rexBuilder, nodes, false); - return Objects.requireNonNull(e); + return requireNonNull(e); } /** @@ -2200,13 +2206,15 @@ public static RexNode swapColumnReferences(final RexBuilder rexBuilder, */ public static RexNode swapTableColumnReferences(final RexBuilder rexBuilder, final RexNode node, final @Nullable Map tableMapping, - final Map> ec) { + final @Nullable Map> ec) { RexShuttle visitor = new RexShuttle() { @Override public RexNode visitTableInputRef(RexTableInputRef inputRef) { if (tableMapping != null) { + RexTableInputRef inputRefFinal = inputRef; inputRef = RexTableInputRef.of( - tableMapping.get(inputRef.getTableRef()), + requireNonNull(tableMapping.get(inputRef.getTableRef()), + () -> "tableMapping.get(...) for " + inputRefFinal.getTableRef()), inputRef.getIndex(), inputRef.getType()); } @@ -2241,8 +2249,10 @@ public static RexNode swapColumnTableReferences(final RexBuilder rexBuilder, } } if (tableMapping != null) { + RexTableInputRef inputRefFinal = inputRef; inputRef = RexTableInputRef.of( - tableMapping.get(inputRef.getTableRef()), + requireNonNull(tableMapping.get(inputRef.getTableRef()), + () -> "tableMapping.get(...) for " + inputRefFinal.getTableRef()), inputRef.getIndex(), inputRef.getType()); } @@ -2274,7 +2284,7 @@ public static Set gatherTableReferences(final List nodes) /** * Walks over expressions and builds a bank of common sub-expressions. */ - private static class ExpressionNormalizer extends RexVisitorImpl { + private static class ExpressionNormalizer extends RexVisitorImpl<@Nullable RexNode> { final Map map = new HashMap<>(); final boolean allowDups; @@ -2292,7 +2302,9 @@ protected RexNode register(RexNode expr) { } protected RexNode lookup(RexNode expr) { - return map.get(expr); + return requireNonNull( + map.get(expr), + () -> "missing normalization for expression " + expr); } @Override public RexNode visitInputRef(RexInputRef inputRef) { @@ -2928,10 +2940,10 @@ private static class RangeToRex> RangeToRex(RexNode ref, List list, RexBuilder rexBuilder, RelDataType type) { - this.ref = Objects.requireNonNull(ref); - this.list = Objects.requireNonNull(list); - this.rexBuilder = Objects.requireNonNull(rexBuilder); - this.type = Objects.requireNonNull(type); + this.ref = requireNonNull(ref); + this.list = requireNonNull(list); + this.rexBuilder = requireNonNull(rexBuilder); + this.type = requireNonNull(type); } private void addAnd(RexNode... nodes) { 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 b9cbc1f0cff8..7ad7247a3f05 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexWindowBound.java +++ b/core/src/main/java/org/apache/calcite/rex/RexWindowBound.java @@ -67,6 +67,9 @@ public boolean isFollowing() { * Returns if the bound is CURRENT ROW. * @return if the bound is CURRENT ROW */ + @Pure + @EnsuresNonNullIf(expression = "getOffset()", result = false) + @SuppressWarnings("contracts.conditional.postcondition.not.satisfied") public boolean isCurrentRow() { return false; } diff --git a/core/src/main/java/org/apache/calcite/runtime/ArrayBindable.java b/core/src/main/java/org/apache/calcite/runtime/ArrayBindable.java index a88bc861f481..52815518a27e 100644 --- a/core/src/main/java/org/apache/calcite/runtime/ArrayBindable.java +++ b/core/src/main/java/org/apache/calcite/runtime/ArrayBindable.java @@ -16,13 +16,15 @@ */ package org.apache.calcite.runtime; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Extension to {@link Bindable} that returns rows that are arrays of objects. * *

It also implements {@link Typed}; the {@link #getElementType()} method * must return {@code Object[].class}. */ -public interface ArrayBindable extends Bindable, Typed { +public interface ArrayBindable extends Bindable<@Nullable Object[]>, Typed { // override @Override Class getElementType(); } diff --git a/core/src/main/java/org/apache/calcite/runtime/ArrayEnumeratorCursor.java b/core/src/main/java/org/apache/calcite/runtime/ArrayEnumeratorCursor.java index 11a8bc1a3006..219df429ffcf 100644 --- a/core/src/main/java/org/apache/calcite/runtime/ArrayEnumeratorCursor.java +++ b/core/src/main/java/org/apache/calcite/runtime/ArrayEnumeratorCursor.java @@ -18,18 +18,20 @@ import org.apache.calcite.linq4j.Enumerator; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Implementation of {@link org.apache.calcite.avatica.util.Cursor} on top of an * {@link org.apache.calcite.linq4j.Enumerator} that * returns an array of {@link Object} for each row. */ -public class ArrayEnumeratorCursor extends EnumeratorCursor { +public class ArrayEnumeratorCursor extends EnumeratorCursor<@Nullable Object[]> { /** * Creates an ArrayEnumeratorCursor. * * @param enumerator Enumerator */ - public ArrayEnumeratorCursor(Enumerator enumerator) { + public ArrayEnumeratorCursor(Enumerator<@Nullable Object[]> enumerator) { super(enumerator); } 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 14600adc2a08..610dce860c47 100644 --- a/core/src/main/java/org/apache/calcite/runtime/ConsList.java +++ b/core/src/main/java/org/apache/calcite/runtime/ConsList.java @@ -123,9 +123,9 @@ private ConsList(E first, List rest) { @Override public @Nullable T[] toArray(T @Nullable [] a) { final int s = size(); if (s > castNonNull(a).length) { - a = Arrays.copyOf(a, s); + a = (T[]) Arrays.copyOf(a, s, a.getClass()); } else if (s < a.length) { - a[s] = null; + a[s] = castNonNull(null); } int i = 0; for (ConsList c = this;; c = (ConsList) c.rest) { @@ -140,11 +140,11 @@ private ConsList(E first, List rest) { } } - @Override public int indexOf(Object o) { + @Override public int indexOf(@Nullable Object o) { return toList().indexOf(o); } - @Override public int lastIndexOf(Object o) { + @Override public int lastIndexOf(@Nullable Object o) { return toList().lastIndexOf(o); } } diff --git a/core/src/main/java/org/apache/calcite/runtime/Enumerables.java b/core/src/main/java/org/apache/calcite/runtime/Enumerables.java index 6865695f3f6b..9682a9b5d09b 100644 --- a/core/src/main/java/org/apache/calcite/runtime/Enumerables.java +++ b/core/src/main/java/org/apache/calcite/runtime/Enumerables.java @@ -54,21 +54,21 @@ public static Enumerable slice0(Enumerable enumerable) { /** Converts an {@link Enumerable} over object arrays into an * {@link Enumerable} over {@link Row} objects. */ - public static Enumerable toRow(final Enumerable enumerable) { - return enumerable.select((Function1) Row::asCopy); + public static Enumerable toRow(final Enumerable<@Nullable Object[]> enumerable) { + return enumerable.select((Function1<@Nullable Object[], Row>) Row::asCopy); } /** Converts a supplier of an {@link Enumerable} over object arrays into a * supplier of an {@link Enumerable} over {@link Row} objects. */ public static Supplier> toRow( - final Supplier> supplier) { + final Supplier> supplier) { return () -> toRow(supplier.get()); } @SuppressWarnings("Guava") @Deprecated // to be removed before 2.0 public static com.google.common.base.Supplier> toRow( - final com.google.common.base.Supplier> supplier) { + final com.google.common.base.Supplier> supplier) { return () -> toRow(supplier.get()); } 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 578a6fb0156a..0518178cab28 100644 --- a/core/src/main/java/org/apache/calcite/runtime/FlatLists.java +++ b/core/src/main/java/org/apache/calcite/runtime/FlatLists.java @@ -357,7 +357,7 @@ protected static class Flat1List return h; } - @Override public int indexOf(Object o) { + @Override public int indexOf(@Nullable Object o) { if (o == null) { if (t0 == null) { return 0; @@ -370,7 +370,7 @@ protected static class Flat1List return -1; } - @Override public int lastIndexOf(Object o) { + @Override public int lastIndexOf(@Nullable Object o) { if (o == null) { if (t0 == null) { return 0; @@ -477,7 +477,7 @@ protected static class Flat2List return h; } - @Override public int indexOf(Object o) { + @Override public int indexOf(@Nullable Object o) { if (o == null) { if (t0 == null) { return 0; @@ -496,7 +496,7 @@ protected static class Flat2List return -1; } - @Override public int lastIndexOf(Object o) { + @Override public int lastIndexOf(@Nullable Object o) { if (o == null) { if (t1 == null) { return 1; @@ -614,7 +614,7 @@ protected static class Flat3List return h; } - @Override public int indexOf(Object o) { + @Override public int indexOf(@Nullable Object o) { if (o == null) { if (t0 == null) { return 0; @@ -639,7 +639,7 @@ protected static class Flat3List return -1; } - @Override public int lastIndexOf(Object o) { + @Override public int lastIndexOf(@Nullable Object o) { if (o == null) { if (t2 == null) { return 2; @@ -770,7 +770,7 @@ protected static class Flat4List return h; } - @Override public int indexOf(Object o) { + @Override public int indexOf(@Nullable Object o) { if (o == null) { if (t0 == null) { return 0; @@ -801,7 +801,7 @@ protected static class Flat4List return -1; } - @Override public int lastIndexOf(Object o) { + @Override public int lastIndexOf(@Nullable Object o) { if (o == null) { if (t3 == null) { return 3; @@ -945,7 +945,7 @@ protected static class Flat5List return h; } - @Override public int indexOf(Object o) { + @Override public int indexOf(@Nullable Object o) { if (o == null) { if (t0 == null) { return 0; @@ -982,7 +982,7 @@ protected static class Flat5List return -1; } - @Override public int lastIndexOf(Object o) { + @Override public int lastIndexOf(@Nullable Object o) { if (o == null) { if (t4 == null) { return 4; @@ -1141,7 +1141,7 @@ protected static class Flat6List return h; } - @Override public int indexOf(Object o) { + @Override public int indexOf(@Nullable Object o) { if (o == null) { if (t0 == null) { return 0; @@ -1184,7 +1184,7 @@ protected static class Flat6List return -1; } - @Override public int lastIndexOf(Object o) { + @Override public int lastIndexOf(@Nullable Object o) { if (o == null) { if (t5 == null) { return 5; diff --git a/core/src/main/java/org/apache/calcite/runtime/JsonFunctions.java b/core/src/main/java/org/apache/calcite/runtime/JsonFunctions.java index 9c570d0ca9b8..896ceb200984 100644 --- a/core/src/main/java/org/apache/calcite/runtime/JsonFunctions.java +++ b/core/src/main/java/org/apache/calcite/runtime/JsonFunctions.java @@ -55,8 +55,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import static org.apache.calcite.linq4j.Nullness.castNonNull; import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * A collection of functions used in JSON processing. */ @@ -87,11 +90,11 @@ private static boolean isScalarObject(Object obj) { return true; } - public static String jsonize(Object input) { + public static String jsonize(@Nullable Object input) { return JSON_PATH_JSON_PROVIDER.toJson(input); } - public static Object dejsonize(String input) { + public static @Nullable Object dejsonize(String input) { return JSON_PATH_JSON_PROVIDER.parse(input); } @@ -124,8 +127,8 @@ public static JsonPathContext jsonApiCommonSyntax(JsonValueContext input, String mode = PathMode.STRICT; pathStr = pathSpec; } else { - mode = PathMode.valueOf(matcher.group(1).toUpperCase(Locale.ROOT)); - pathStr = matcher.group(2); + mode = PathMode.valueOf(castNonNull(matcher.group(1)).toUpperCase(Locale.ROOT)); + pathStr = castNonNull(matcher.group(2)); } DocumentContext ctx; switch (mode) { @@ -133,7 +136,7 @@ public static JsonPathContext jsonApiCommonSyntax(JsonValueContext input, String if (input.hasException()) { return JsonPathContext.withStrictException(pathSpec, input.exc); } - ctx = JsonPath.parse(input.obj, + ctx = JsonPath.parse(input.obj(), Configuration .builder() .jsonProvider(JSON_PATH_JSON_PROVIDER) @@ -144,7 +147,7 @@ public static JsonPathContext jsonApiCommonSyntax(JsonValueContext input, String if (input.hasException()) { return JsonPathContext.withJavaObj(PathMode.LAX, null); } - ctx = JsonPath.parse(input.obj, + ctx = JsonPath.parse(input.obj(), Configuration .builder() .options(Option.SUPPRESS_EXCEPTIONS) @@ -623,7 +626,7 @@ public static String jsonRemove(String input, String... pathSpecs) { public static String jsonRemove(JsonValueContext input, String... pathSpecs) { try { - DocumentContext ctx = JsonPath.parse(input.obj, + DocumentContext ctx = JsonPath.parse(input.obj(), Configuration .builder() .options(Option.SUPPRESS_EXCEPTIONS) @@ -767,7 +770,7 @@ private JsonValueContext(@Nullable Object obj, @Nullable Exception exc) { this.exc = exc; } - public static JsonValueContext withJavaObj(Object obj) { + public static JsonValueContext withJavaObj(@Nullable Object obj) { return new JsonValueContext(obj, null); } @@ -775,6 +778,11 @@ public static JsonValueContext withException(Exception exc) { return new JsonValueContext(null, exc); } + Object obj() { + return requireNonNull(obj, "json object must not be null"); + } + + @EnsuresNonNullIf(expression = "exc", result = true) public boolean hasException() { return exc != null; } 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 62e90f111728..84defdd5e323 100644 --- a/core/src/main/java/org/apache/calcite/runtime/ResultSetEnumerable.java +++ b/core/src/main/java/org/apache/calcite/runtime/ResultSetEnumerable.java @@ -312,6 +312,7 @@ private Enumerator enumeratorBasedOnPreparedStatement() { } private void setTimeoutIfPossible(Statement statement) throws SQLException { + Long queryStart = this.queryStart; if (timeout == 0 || queryStart == null) { return; } 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 cf8402d8a35b..81a977046d48 100644 --- a/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java +++ b/core/src/main/java/org/apache/calcite/runtime/SqlFunctions.java @@ -124,15 +124,15 @@ public class SqlFunctions { "Alpha", "XDigit", "Digit", "Alnum", "Punct", "Graph", "Print", "Blank", "Cntrl", "Space" }; @SuppressWarnings("unused") - private static final Function1> ARRAY_CARTESIAN_PRODUCT = + private static final Function1> ARRAY_CARTESIAN_PRODUCT = lists -> { - final List> enumerators = new ArrayList<>(); + final List> enumerators = new ArrayList<>(); for (Object list : lists) { enumerators.add(Linq4j.enumerator((List) list)); } - final Enumerator> product = Linq4j.product(enumerators); - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { + final Enumerator> product = Linq4j.product(enumerators); + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { return Linq4j.transform(product, List::toArray); } }; @@ -2608,7 +2608,8 @@ public static long sequenceNextValue(String key) { } private static AtomicLong getAtomicLong(String key) { - final Map map = THREAD_SEQUENCES.get(); + final Map map = requireNonNull(THREAD_SEQUENCES.get(), + "THREAD_SEQUENCES.get()"); AtomicLong atomic = map.get(key); if (atomic == null) { atomic = new AtomicLong(); @@ -2969,8 +2970,9 @@ public static int subtractMonths(long t0, long t1) { return ((Row) structObject).getObject(index); } else { Class beanClass = structObject.getClass(); + requireNonNull(fieldName, "fieldName"); try { - Field structField = beanClass.getDeclaredField(requireNonNull(fieldName, "fieldName")); + Field structField = beanClass.getDeclaredField(fieldName); return structField.get(structObject); } catch (NoSuchFieldException | IllegalAccessException ex) { throw RESOURCE.failedToAccessField(fieldName, beanClass.getName()).ex(ex); diff --git a/core/src/main/java/org/apache/calcite/runtime/TrustAllSslSocketFactory.java b/core/src/main/java/org/apache/calcite/runtime/TrustAllSslSocketFactory.java index ba09e5ac3699..9bab3dde09e6 100644 --- a/core/src/main/java/org/apache/calcite/runtime/TrustAllSslSocketFactory.java +++ b/core/src/main/java/org/apache/calcite/runtime/TrustAllSslSocketFactory.java @@ -16,6 +16,9 @@ */ package org.apache.calcite.runtime; + +import org.checkerframework.checker.nullness.qual.Nullable; + import java.io.IOException; import java.net.InetAddress; import java.net.Socket; @@ -26,6 +29,10 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + +import static java.util.Objects.requireNonNull; + /** * Socket factory that trusts all SSL connections. */ @@ -46,7 +53,7 @@ protected TrustAllSslSocketFactory() { } catch (Exception e) { e.printStackTrace(); } - this.sslSocketFactory = factory; + this.sslSocketFactory = requireNonNull(factory, "sslSocketFactory"); } @Override public Socket createSocket() throws IOException { @@ -97,7 +104,7 @@ public static SSLSocketFactory getDefaultSSLSocketFactory() { * * @return SSLSocketFactory */ - public static SSLSocketFactory createSSLSocketFactory() { + public static @Nullable SSLSocketFactory createSSLSocketFactory() { SSLSocketFactory sslsocketfactory = null; TrustManager[] trustAllCerts = {new DummyTrustManager()}; try { @@ -114,7 +121,7 @@ public static SSLSocketFactory createSSLSocketFactory() { * certificates. */ private static class DummyTrustManager implements X509TrustManager { @Override public X509Certificate[] getAcceptedIssuers() { - return null; + return castNonNull(null); } @Override public void checkClientTrusted( 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 da9367461fe8..13d270fe7be2 100644 --- a/core/src/main/java/org/apache/calcite/runtime/XmlFunctions.java +++ b/core/src/main/java/org/apache/calcite/runtime/XmlFunctions.java @@ -51,6 +51,8 @@ import static org.apache.calcite.linq4j.Nullness.castNonNull; import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * A collection of functions used in Xml processing. */ @@ -78,9 +80,12 @@ private XmlFunctions() { try { NodeList nodes = (NodeList) xpathExpression .evaluate(new InputSource(new StringReader(input)), XPathConstants.NODESET); - List result = new ArrayList<>(); + List<@Nullable String> result = new ArrayList<>(); for (int i = 0; i < nodes.getLength(); i++) { - result.add(nodes.item(i).getFirstChild().getTextContent()); + Node item = castNonNull(nodes.item(i)); + Node firstChild = requireNonNull(item.getFirstChild(), + () -> "firstChild of node " + item); + result.add(firstChild.getTextContent()); } return StringUtils.join(result, " "); } catch (XPathExpressionException e) { @@ -134,7 +139,7 @@ private XmlFunctions() { NodeList nodes = (NodeList) xpathExpression .evaluate(new InputSource(new StringReader(xml)), XPathConstants.NODESET); for (int i = 0; i < nodes.getLength(); i++) { - result.add(convertNodeToString(nodes.item(i))); + result.add(convertNodeToString(castNonNull(nodes.item(i)))); } return StringUtils.join(result, ""); } catch (XPathExpressionException e) { @@ -190,7 +195,7 @@ private static SimpleNamespaceContext extractNamespaceContext(String namespace) Map namespaceMap = new HashMap<>(); Matcher matcher = EXTRACT_NAMESPACE_PATTERN.matcher(namespace); while (matcher.find()) { - namespaceMap.put(matcher.group(1), matcher.group(3)); + namespaceMap.put(castNonNull(matcher.group(1)), castNonNull(matcher.group(3))); } return new SimpleNamespaceContext(namespaceMap); } diff --git a/core/src/main/java/org/apache/calcite/schema/FilterableTable.java b/core/src/main/java/org/apache/calcite/schema/FilterableTable.java index 8340a3229f08..718fcdba84b0 100644 --- a/core/src/main/java/org/apache/calcite/schema/FilterableTable.java +++ b/core/src/main/java/org/apache/calcite/schema/FilterableTable.java @@ -20,6 +20,8 @@ import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.rex.RexNode; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -38,5 +40,5 @@ public interface FilterableTable extends Table { * If it cannot implement a filter, it should leave it in the list. * Any filters remaining will be implemented by the consuming Calcite * operator. */ - Enumerable scan(DataContext root, List filters); + Enumerable<@Nullable Object[]> scan(DataContext root, List filters); } diff --git a/core/src/main/java/org/apache/calcite/schema/ModifiableTable.java b/core/src/main/java/org/apache/calcite/schema/ModifiableTable.java index 3c6b1c99d78b..1037baf78aea 100644 --- a/core/src/main/java/org/apache/calcite/schema/ModifiableTable.java +++ b/core/src/main/java/org/apache/calcite/schema/ModifiableTable.java @@ -39,7 +39,7 @@ public interface ModifiableTable extends QueryableTable { /** Returns the modifiable collection. * Modifying the collection will change the table's contents. */ - Collection getModifiableCollection(); + @Nullable Collection getModifiableCollection(); /** Creates a relational expression that modifies this table. */ TableModify toModificationRel( 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 924935213cb0..89d7070bf186 100644 --- a/core/src/main/java/org/apache/calcite/schema/Path.java +++ b/core/src/main/java/org/apache/calcite/schema/Path.java @@ -18,8 +18,6 @@ import org.apache.calcite.util.Pair; -import org.checkerframework.checker.nullness.qual.Nullable; - import java.util.List; import java.util.RandomAccess; @@ -33,7 +31,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(); @@ -41,5 +39,5 @@ public interface Path extends List>, RandomAccess List names(); /** Returns the schemas of this path. */ - List<@Nullable Schema> schemas(); + List schemas(); } diff --git a/core/src/main/java/org/apache/calcite/schema/ProjectableFilterableTable.java b/core/src/main/java/org/apache/calcite/schema/ProjectableFilterableTable.java index b179ab84f8e0..366536312fe0 100644 --- a/core/src/main/java/org/apache/calcite/schema/ProjectableFilterableTable.java +++ b/core/src/main/java/org/apache/calcite/schema/ProjectableFilterableTable.java @@ -58,6 +58,6 @@ public interface ProjectableFilterableTable extends Table { * for each row an array of column values, one value for each ordinal in * {@code projects}. */ - Enumerable scan(DataContext root, List filters, + Enumerable<@Nullable Object[]> scan(DataContext root, List filters, int @Nullable [] projects); } diff --git a/core/src/main/java/org/apache/calcite/schema/ScannableTable.java b/core/src/main/java/org/apache/calcite/schema/ScannableTable.java index 0c75478a19d1..31b3c6896c88 100644 --- a/core/src/main/java/org/apache/calcite/schema/ScannableTable.java +++ b/core/src/main/java/org/apache/calcite/schema/ScannableTable.java @@ -19,6 +19,8 @@ import org.apache.calcite.DataContext; import org.apache.calcite.linq4j.Enumerable; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Table that can be scanned without creating an intermediate relational * expression. @@ -26,5 +28,5 @@ public interface ScannableTable extends Table { /** Returns an enumerator over the rows in this Table. Each row is represented * as an array of its column values. */ - Enumerable scan(DataContext root); + Enumerable<@Nullable Object[]> scan(DataContext root); } diff --git a/core/src/main/java/org/apache/calcite/schema/Schema.java b/core/src/main/java/org/apache/calcite/schema/Schema.java index 54a75c1ea6f6..fa5994379d62 100644 --- a/core/src/main/java/org/apache/calcite/schema/Schema.java +++ b/core/src/main/java/org/apache/calcite/schema/Schema.java @@ -125,7 +125,7 @@ public interface Schema { * @param name Name of this schema * @return Expression by which this schema can be referenced in generated code */ - Expression getExpression(SchemaPlus parentSchema, String name); + Expression getExpression(@Nullable SchemaPlus parentSchema, String name); /** Returns whether the user is allowed to create new tables, functions * and sub-schemas in this schema, in addition to those returned automatically 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 c5e8bf17241c..70526032b0bb 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 { @Override boolean isMutable(); /** Returns an underlying object. */ - @Nullable 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 847beb749ec5..f857ba3fc4f7 100644 --- a/core/src/main/java/org/apache/calcite/schema/Schemas.java +++ b/core/src/main/java/org/apache/calcite/schema/Schemas.java @@ -57,10 +57,11 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Objects; import static org.apache.calcite.jdbc.CalciteSchema.LatticeEntry; +import static java.util.Objects.requireNonNull; + /** * Utility functions for schemas. */ @@ -200,8 +201,13 @@ public static Queryable queryable(DataContext root, Class clazz, SchemaPlus schema = root.getRootSchema(); for (Iterator iterator = names.iterator();;) { String name = iterator.next(); + requireNonNull(schema, "schema"); if (iterator.hasNext()) { - schema = schema.getSubSchema(name); + SchemaPlus next = schema.getSubSchema(name); + if (next == null) { + throw new IllegalArgumentException("schema " + name + " is not found in " + schema); + } + schema = next; } else { return queryable(root, schema, clazz, name); } @@ -211,13 +217,17 @@ public static Queryable queryable(DataContext root, Class clazz, /** Returns a {@link Queryable}, given a schema and table name. */ public static Queryable queryable(DataContext root, SchemaPlus schema, Class clazz, String tableName) { - QueryableTable table = (QueryableTable) schema.getTable(tableName); - return table.asQueryable(root.getQueryProvider(), schema, tableName); + QueryableTable table = (QueryableTable) requireNonNull( + schema.getTable(tableName), + () -> "table " + tableName + " is not found in " + schema); + QueryProvider queryProvider = requireNonNull(root.getQueryProvider(), + "root.getQueryProvider()"); + return table.asQueryable(queryProvider, schema, tableName); } /** Returns an {@link org.apache.calcite.linq4j.Enumerable} over the rows of * a given table, representing each row as an object array. */ - public static Enumerable enumerable(final ScannableTable table, + public static Enumerable<@Nullable Object[]> enumerable(final ScannableTable table, final DataContext root) { return table.scan(root); } @@ -225,7 +235,7 @@ public static Enumerable enumerable(final ScannableTable table, /** Returns an {@link org.apache.calcite.linq4j.Enumerable} over the rows of * a given table, not applying any filters, representing each row as an object * array. */ - public static Enumerable enumerable(final FilterableTable table, + public static Enumerable<@Nullable Object[]> enumerable(final FilterableTable table, final DataContext root) { return table.scan(root, new ArrayList<>()); } @@ -233,10 +243,11 @@ public static Enumerable enumerable(final FilterableTable table, /** Returns an {@link org.apache.calcite.linq4j.Enumerable} over the rows of * a given table, not applying any filters and projecting all columns, * representing each row as an object array. */ - public static Enumerable enumerable( + public static Enumerable<@Nullable Object[]> enumerable( final ProjectableFilterableTable table, final DataContext root) { + JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory"); return table.scan(root, new ArrayList<>(), - identity(table.getRowType(root.getTypeFactory()).getFieldCount())); + identity(table.getRowType(typeFactory).getFieldCount())); } private static int[] identity(int count) { @@ -250,13 +261,18 @@ private static int[] identity(int count) { /** Returns an {@link org.apache.calcite.linq4j.Enumerable} over object * arrays, given a fully-qualified table name which leads to a * {@link ScannableTable}. */ - public static Table table(DataContext root, String... names) { + public static @Nullable Table table(DataContext root, String... names) { SchemaPlus schema = root.getRootSchema(); final List nameList = Arrays.asList(names); for (Iterator iterator = nameList.iterator();;) { String name = iterator.next(); + requireNonNull(schema, "schema"); if (iterator.hasNext()) { - schema = schema.getSubSchema(name); + SchemaPlus next = schema.getSubSchema(name); + if (next == null) { + throw new IllegalArgumentException("schema " + name + " is not found in " + schema); + } + schema = next; } else { return schema.getTable(name); } @@ -266,7 +282,7 @@ public static Table table(DataContext root, String... names) { /** Parses and validates a SQL query. For use within Calcite only. */ public static CalcitePrepare.ParseResult parse( final CalciteConnection connection, final CalciteSchema schema, - final List schemaPath, final String sql) { + final @Nullable List schemaPath, final String sql) { final CalcitePrepare prepare = CalcitePrepare.DEFAULT_FACTORY.apply(); final ImmutableMap propValues = ImmutableMap.of(); @@ -319,7 +335,7 @@ public static CalcitePrepare.AnalyzeViewResult analyzeView( /** Prepares a SQL query for execution. For use within Calcite only. */ public static CalcitePrepare.CalciteSignature prepare( final CalciteConnection connection, final CalciteSchema schema, - final List schemaPath, final String sql, + final @Nullable List schemaPath, final String sql, final ImmutableMap map) { final CalcitePrepare prepare = CalcitePrepare.DEFAULT_FACTORY.apply(); final CalcitePrepare.Context context = @@ -448,7 +464,7 @@ public static List getStarTables( final List list = getLatticeEntries(schema); return Util.transform(list, entry -> { final CalciteSchema.TableEntry starTable = - Objects.requireNonNull(entry).getStarTable(); + requireNonNull(entry).getStarTable(); assert starTable.getTable().getJdbcTableType() == Schema.TableType.STAR; return entry.getStarTable(); @@ -489,18 +505,19 @@ private static void gatherLattices(CalciteSchema schema, */ public static @Nullable CalciteSchema subSchema(CalciteSchema schema, Iterable names) { + @Nullable CalciteSchema current = schema; for (String string : names) { - if (schema == null) { + if (current == null) { return null; } - schema = schema.getSubSchema(string, false); + current = current.getSubSchema(string, false); } - return schema; + return current; } /** Generates a table name that is unique within the given schema. */ public static String uniqueTableName(CalciteSchema schema, String base) { - String t = Objects.requireNonNull(base); + String t = requireNonNull(base); for (int x = 0; schema.getTable(t, true) != null; x++) { t = base + x; } @@ -510,7 +527,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(); @@ -528,11 +545,15 @@ public static Path path(CalciteSchema rootSchema, Iterable names) { if (!iterator.hasNext()) { return path(builder.build()); } - schema = schema.getSubSchema(name); + Schema next = schema.getSubSchema(name); + if (next == null) { + throw new IllegalArgumentException("schema " + name + " is not found in " + schema); + } + schema = next; } } - public static PathImpl path(ImmutableList> build) { + public static PathImpl path(ImmutableList> build) { return new PathImpl(build); } @@ -565,7 +586,7 @@ private static class DummyDataContext implements DataContext { return connection.getTypeFactory(); } - @Override public @Nullable QueryProvider getQueryProvider() { + @Override public QueryProvider getQueryProvider() { return connection; } @@ -576,13 +597,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; } @@ -596,7 +617,7 @@ private static class PathImpl return pairs.hashCode(); } - @Override public Pair get(int index) { + @Override public Pair get(int index) { return pairs.get(index); } @@ -623,7 +644,7 @@ private static class PathImpl }; } - @Override public List<@Nullable Schema> schemas() { + @Override public List schemas() { return Pair.right(pairs); } } diff --git a/core/src/main/java/org/apache/calcite/schema/Statistic.java b/core/src/main/java/org/apache/calcite/schema/Statistic.java index c871fd144cf7..2e4307f68fbc 100644 --- a/core/src/main/java/org/apache/calcite/schema/Statistic.java +++ b/core/src/main/java/org/apache/calcite/schema/Statistic.java @@ -34,7 +34,7 @@ */ public interface Statistic { /** Returns the approximate number of rows in the table. */ - @Nullable default Double getRowCount() { + default @Nullable Double getRowCount() { return null; } diff --git a/core/src/main/java/org/apache/calcite/schema/Statistics.java b/core/src/main/java/org/apache/calcite/schema/Statistics.java index d290d24377cd..85de175989e5 100644 --- a/core/src/main/java/org/apache/calcite/schema/Statistics.java +++ b/core/src/main/java/org/apache/calcite/schema/Statistics.java @@ -39,14 +39,14 @@ private Statistics() { }; /** Returns a statistic with a given set of referential constraints. */ - public static Statistic of(final List referentialConstraints) { + public static Statistic of(@Nullable List referentialConstraints) { return of(null, null, referentialConstraints, null); } /** Returns a statistic with a given row count and set of unique keys. */ public static Statistic of(final double rowCount, - final List keys) { + final @Nullable List keys) { return of(rowCount, keys, null, null); } @@ -54,17 +54,17 @@ public static Statistic of(final double rowCount, /** Returns a statistic with a given row count, set of unique keys, * and collations. */ public static Statistic of(final double rowCount, - final List keys, - final List collations) { + final @Nullable List keys, + final @Nullable List collations) { return of(rowCount, keys, null, collations); } /** Returns a statistic with a given row count, set of unique keys, * referential constraints, and collations. */ public static Statistic of(final @Nullable Double rowCount, - final List keys, - final List referentialConstraints, - final List collations) { + final @Nullable List keys, + final @Nullable List referentialConstraints, + final @Nullable List collations) { List keysCopy = keys == null ? ImmutableList.of() : ImmutableList.copyOf(keys); List referentialConstraintsCopy = referentialConstraints == null ? null : ImmutableList.copyOf(referentialConstraints); @@ -85,15 +85,15 @@ public static Statistic of(final @Nullable Double rowCount, return false; } - @Override public List getKeys() { + @Override public @Nullable List getKeys() { return keysCopy; } - @Override public List getReferentialConstraints() { + @Override public @Nullable List getReferentialConstraints() { return referentialConstraintsCopy; } - @Override public List getCollations() { + @Override public @Nullable List getCollations() { return collationsCopy; } }; diff --git a/core/src/main/java/org/apache/calcite/schema/TableFactory.java b/core/src/main/java/org/apache/calcite/schema/TableFactory.java index 9875334d8dff..780bf2e6815c 100644 --- a/core/src/main/java/org/apache/calcite/schema/TableFactory.java +++ b/core/src/main/java/org/apache/calcite/schema/TableFactory.java @@ -18,6 +18,8 @@ import org.apache.calcite.rel.type.RelDataType; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Map; /** @@ -78,10 +80,11 @@ public interface TableFactory { * @param name Name of this table * @param operand The "operand" JSON property * @param rowType Row type. Specified if the "columns" JSON property. + * @return created table */ T create( SchemaPlus schema, String name, Map operand, - RelDataType rowType); + @Nullable RelDataType rowType); } diff --git a/core/src/main/java/org/apache/calcite/schema/Wrapper.java b/core/src/main/java/org/apache/calcite/schema/Wrapper.java index 6a575ede0861..91e43cac7d70 100644 --- a/core/src/main/java/org/apache/calcite/schema/Wrapper.java +++ b/core/src/main/java/org/apache/calcite/schema/Wrapper.java @@ -16,13 +16,25 @@ */ package org.apache.calcite.schema; +import org.apiguardian.api.API; import org.checkerframework.checker.nullness.qual.Nullable; +import static java.util.Objects.requireNonNull; + /** * Mix-in interface that allows you to find sub-objects. */ public interface Wrapper { /** Finds an instance of an interface implemented by this object, * or returns null if this object does not support that interface. */ - @Nullable C unwrap(Class aClass); + @Nullable C unwrap(Class aClass); + + /** Finds an instance of an interface implemented by this object, + * or throws NullPointerException if this object does not support + * that interface. */ + @API(since = "1.27", status = API.Status.INTERNAL) + default C unwrapOrThrow(Class aClass) { + return requireNonNull(unwrap(aClass), + () -> "Can't unwrap " + aClass + " from " + this); + } } diff --git a/core/src/main/java/org/apache/calcite/schema/impl/AbstractSchema.java b/core/src/main/java/org/apache/calcite/schema/impl/AbstractSchema.java index 36ad56f53ba8..04072f4cd98a 100644 --- a/core/src/main/java/org/apache/calcite/schema/impl/AbstractSchema.java +++ b/core/src/main/java/org/apache/calcite/schema/impl/AbstractSchema.java @@ -36,6 +36,8 @@ import java.util.Map; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** * Abstract implementation of {@link Schema}. * @@ -65,7 +67,8 @@ public AbstractSchema() { return this; } - @Override public Expression getExpression(SchemaPlus parentSchema, String name) { + @Override public Expression getExpression(@Nullable SchemaPlus parentSchema, String name) { + requireNonNull(parentSchema, "parentSchema"); return Schemas.subSchemaExpression(parentSchema, name, getClass()); } @@ -84,7 +87,8 @@ protected Map getTableMap() { } @Override public final Set getTableNames() { - return getTableMap().keySet(); + //noinspection RedundantCast + return (Set) getTableMap().keySet(); } @Override public final @Nullable Table getTable(String name) { @@ -110,7 +114,8 @@ protected Map getTypeMap() { } @Override public Set getTypeNames() { - return getTypeMap().keySet(); + //noinspection RedundantCast + return (Set) getTypeMap().keySet(); } /** @@ -153,7 +158,8 @@ protected Map getSubSchemaMap() { } @Override public final Set getSubSchemaNames() { - return getSubSchemaMap().keySet(); + //noinspection RedundantCast + return (Set) getSubSchemaMap().keySet(); } @Override public final @Nullable Schema getSubSchema(String name) { 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 19c05d6c522a..7f7d7b0ae92c 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 @@ -48,7 +48,7 @@ protected AbstractTable() { return Schema.TableType.TABLE; } - @Override public @Nullable C unwrap(Class aClass) { + @Override public @Nullable C unwrap(Class aClass) { if (aClass.isInstance(this)) { return aClass.cast(this); } diff --git a/core/src/main/java/org/apache/calcite/schema/impl/DelegatingSchema.java b/core/src/main/java/org/apache/calcite/schema/impl/DelegatingSchema.java index a1add6bc155b..e63f518878bf 100644 --- a/core/src/main/java/org/apache/calcite/schema/impl/DelegatingSchema.java +++ b/core/src/main/java/org/apache/calcite/schema/impl/DelegatingSchema.java @@ -57,7 +57,7 @@ public DelegatingSchema(Schema schema) { return schema.snapshot(version); } - @Override public Expression getExpression(SchemaPlus parentSchema, String name) { + @Override public Expression getExpression(@Nullable SchemaPlus parentSchema, String name) { return schema.getExpression(parentSchema, name); } diff --git a/core/src/main/java/org/apache/calcite/schema/impl/ListTransientTable.java b/core/src/main/java/org/apache/calcite/schema/impl/ListTransientTable.java index 12485e7f6e7a..0ee6ec4581ab 100644 --- a/core/src/main/java/org/apache/calcite/schema/impl/ListTransientTable.java +++ b/core/src/main/java/org/apache/calcite/schema/impl/ListTransientTable.java @@ -41,12 +41,16 @@ import org.apache.calcite.schema.Schemas; import org.apache.calcite.schema.TransientTable; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import static java.util.Objects.requireNonNull; + /** * {@link TransientTable} backed by a Java list. It will be automatically added to the * current schema when {@link #scan(DataContext)} method gets called. @@ -73,8 +77,8 @@ public ListTransientTable(String name, RelDataType rowType) { Prepare.CatalogReader catalogReader, RelNode child, TableModify.Operation operation, - List updateColumnList, - List sourceExpressionList, + @Nullable List updateColumnList, + @Nullable List sourceExpressionList, boolean flattened) { return LogicalTableModify.create(table, catalogReader, child, operation, updateColumnList, sourceExpressionList, flattened); @@ -84,15 +88,16 @@ public ListTransientTable(String name, RelDataType rowType) { return rows; } - @Override public Enumerable scan(DataContext root) { + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { // add the table into the schema, so that it is accessible by any potential operator - root.getRootSchema().add(name, this); + requireNonNull(root.getRootSchema(), "root.getRootSchema()") + .add(name, this); final AtomicBoolean cancelFlag = DataContext.Variable.CANCEL_FLAG.get(root); - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { - return new Enumerator() { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { + return new Enumerator<@Nullable Object[]>() { private final List list = new ArrayList(rows); private int i = -1; diff --git a/core/src/main/java/org/apache/calcite/schema/impl/MaterializedViewTable.java b/core/src/main/java/org/apache/calcite/schema/impl/MaterializedViewTable.java index c0b9ea7bdd7e..f2a815c3cd03 100644 --- a/core/src/main/java/org/apache/calcite/schema/impl/MaterializedViewTable.java +++ b/core/src/main/java/org/apache/calcite/schema/impl/MaterializedViewTable.java @@ -30,6 +30,8 @@ import org.apache.calcite.schema.Table; import org.apache.calcite.schema.TranslatableTable; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.reflect.Type; import java.sql.DriverManager; import java.sql.SQLException; @@ -67,7 +69,7 @@ public MaterializedViewTable(Type elementType, RelProtoDataType relDataType, String viewSql, List viewSchemaPath, - List viewPath, + @Nullable List viewPath, MaterializationKey key) { super(elementType, relDataType, viewSql, viewSchemaPath, viewPath); this.key = key; @@ -75,8 +77,8 @@ public MaterializedViewTable(Type elementType, /** Table macro that returns a materialized view. */ public static MaterializedViewTableMacro create(final CalciteSchema schema, - final String viewSql, final List viewSchemaPath, List viewPath, - final String suggestedTableName, boolean existing) { + final String viewSql, final @Nullable List viewSchemaPath, List viewPath, + final @Nullable String suggestedTableName, boolean existing) { return new MaterializedViewTableMacro(schema, viewSql, viewSchemaPath, viewPath, suggestedTableName, existing); } @@ -101,7 +103,8 @@ public static class MaterializedViewTableMacro private final MaterializationKey key; private MaterializedViewTableMacro(CalciteSchema schema, String viewSql, - List viewSchemaPath, List viewPath, String suggestedTableName, + @Nullable List viewSchemaPath, List viewPath, + @Nullable String suggestedTableName, boolean existing) { super(schema, viewSql, viewSchemaPath != null ? viewSchemaPath : schema.path(null), viewPath, diff --git a/core/src/main/java/org/apache/calcite/schema/impl/ModifiableViewTable.java b/core/src/main/java/org/apache/calcite/schema/impl/ModifiableViewTable.java index 5a2ce4b4a0dc..7ed7026aac1f 100644 --- a/core/src/main/java/org/apache/calcite/schema/impl/ModifiableViewTable.java +++ b/core/src/main/java/org/apache/calcite/schema/impl/ModifiableViewTable.java @@ -50,6 +50,8 @@ import static org.apache.calcite.sql.validate.SqlValidatorUtil.mapNameToIndex; +import static java.util.Objects.requireNonNull; + /** Extension to {@link ViewTable} that is modifiable. */ public class ModifiableViewTable extends ViewTable implements ModifiableView, Wrapper { @@ -61,7 +63,7 @@ public class ModifiableViewTable extends ViewTable /** Creates a ModifiableViewTable. */ public ModifiableViewTable(Type elementType, RelProtoDataType rowType, - String viewSql, List schemaPath, List viewPath, + String viewSql, List schemaPath, @Nullable List viewPath, Table table, Path tablePath, RexNode constraint, ImmutableIntList columnMapping) { super(elementType, rowType, viewSql, schemaPath, viewPath); @@ -89,7 +91,7 @@ public ModifiableViewTable(Type elementType, RelProtoDataType rowType, return tablePath; } - @Override public @Nullable C unwrap(Class aClass) { + @Override public @Nullable C unwrap(Class aClass) { if (aClass.isInstance(initializerExpressionFactory)) { return aClass.cast(initializerExpressionFactory); } else if (aClass.isInstance(table)) { @@ -160,10 +162,11 @@ private static ImmutableIntList getNewColumnMapping(Table underlying, newMapping.addAll(oldColumnMapping); int newMappedIndex = baseColumns.size(); for (RelDataTypeField extendedColumn : extendedColumns) { - if (nameToIndex.containsKey(extendedColumn.getName())) { + String extendedColumnName = extendedColumn.getName(); + if (nameToIndex.containsKey(extendedColumnName)) { // The extended column duplicates a column in the underlying table. // Map to the index in the underlying table. - newMapping.add(nameToIndex.get(extendedColumn.getName())); + newMapping.add(nameToIndex.get(extendedColumnName)); } else { // The extended column is not in the underlying table. newMapping.add(newMappedIndex++); @@ -197,8 +200,9 @@ private ModifiableViewTableInitializerExpressionFactory() { @Override public ColumnStrategy generationStrategy(RelOptTable table, int iColumn) { - final ModifiableViewTable viewTable = - table.unwrap(ModifiableViewTable.class); + final ModifiableViewTable viewTable = requireNonNull( + table.unwrap(ModifiableViewTable.class), + () -> "unable to unwrap ModifiableViewTable from " + table); assert iColumn < viewTable.columnMapping.size(); // Use the view constraint to generate the default value if the column is @@ -224,7 +228,9 @@ private ModifiableViewTableInitializerExpressionFactory() { @Override public RexNode newColumnDefaultValue(RelOptTable table, int iColumn, InitializerContext context) { - final ModifiableViewTable viewTable = table.unwrap(ModifiableViewTable.class); + final ModifiableViewTable viewTable = requireNonNull( + table.unwrap(ModifiableViewTable.class), + () -> "unable to unwrap ModifiableViewTable from " + table); assert iColumn < viewTable.columnMapping.size(); final RexBuilder rexBuilder = context.getRexBuilder(); final RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory(); diff --git a/core/src/main/java/org/apache/calcite/schema/impl/ScalarFunctionImpl.java b/core/src/main/java/org/apache/calcite/schema/impl/ScalarFunctionImpl.java index e095b5924c6e..162a10239b97 100644 --- a/core/src/main/java/org/apache/calcite/schema/impl/ScalarFunctionImpl.java +++ b/core/src/main/java/org/apache/calcite/schema/impl/ScalarFunctionImpl.java @@ -32,6 +32,8 @@ import com.google.common.collect.ImmutableMultimap; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -111,7 +113,7 @@ public static ImmutableMultimap functions(Class clazz) { * @param methodName Method name (typically "eval") * @return created {@link ScalarFunction} or null */ - public static ScalarFunction create(Class clazz, String methodName) { + public static @Nullable ScalarFunction create(Class clazz, String methodName) { final Method method = findMethod(clazz, methodName); if (method == null) { return null; diff --git a/core/src/main/java/org/apache/calcite/schema/impl/TableFunctionImpl.java b/core/src/main/java/org/apache/calcite/schema/impl/TableFunctionImpl.java index 73e3dd64218e..ecad1b88761c 100644 --- a/core/src/main/java/org/apache/calcite/schema/impl/TableFunctionImpl.java +++ b/core/src/main/java/org/apache/calcite/schema/impl/TableFunctionImpl.java @@ -47,6 +47,8 @@ import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * Implementation of {@link org.apache.calcite.schema.TableFunction} based on a * method. @@ -63,7 +65,7 @@ private TableFunctionImpl(Method method, CallImplementor implementor) { /** Creates a {@link TableFunctionImpl} from a class, looking for an "eval" * method. Returns null if there is no such method. */ - public static TableFunction create(Class clazz) { + public static @Nullable TableFunction create(Class clazz) { return create(clazz, "eval"); } @@ -78,7 +80,7 @@ public static TableFunction create(Class clazz) { } /** Creates a {@link TableFunctionImpl} from a method. */ - public static TableFunction create(final Method method) { + public static @Nullable TableFunction create(final Method method) { if (!Modifier.isStatic(method.getModifiers())) { Class clazz = method.getDeclaringClass(); if (!classHasPublicZeroArgsConstructor(clazz)) { @@ -150,9 +152,9 @@ private Table apply(List arguments) { method.getDeclaringClass().getConstructor(); o = constructor.newInstance(); } - //noinspection unchecked - final Object table = method.invoke(o, arguments.toArray()); - return (Table) table; + return (Table) requireNonNull( + method.invoke(o, arguments.toArray()), + () -> "got null from " + method + " with arguments " + arguments); } catch (IllegalArgumentException e) { throw RESOURCE.illegalArgumentForTableFunctionCall( method.toString(), diff --git a/core/src/main/java/org/apache/calcite/schema/impl/TableMacroImpl.java b/core/src/main/java/org/apache/calcite/schema/impl/TableMacroImpl.java index 77ac0ebb0fea..8c317e0a795c 100644 --- a/core/src/main/java/org/apache/calcite/schema/impl/TableMacroImpl.java +++ b/core/src/main/java/org/apache/calcite/schema/impl/TableMacroImpl.java @@ -30,6 +30,8 @@ import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * Implementation of {@link org.apache.calcite.schema.TableMacro} based on a * method. @@ -81,8 +83,9 @@ private TableMacroImpl(Method method) { method.getDeclaringClass().getConstructor(); o = constructor.newInstance(); } - //noinspection unchecked - return (TranslatableTable) method.invoke(o, arguments.toArray()); + return (TranslatableTable) requireNonNull( + method.invoke(o, arguments.toArray()), + () -> "got null from " + method + " with arguments " + arguments); } catch (IllegalArgumentException e) { throw new RuntimeException("Expected " + Arrays.toString(method.getParameterTypes()) + " actual " diff --git a/core/src/main/java/org/apache/calcite/schema/impl/ViewTableMacro.java b/core/src/main/java/org/apache/calcite/schema/impl/ViewTableMacro.java index ee79d3731259..fe989019e5ab 100644 --- a/core/src/main/java/org/apache/calcite/schema/impl/ViewTableMacro.java +++ b/core/src/main/java/org/apache/calcite/schema/impl/ViewTableMacro.java @@ -90,7 +90,7 @@ public ViewTableMacro(CalciteSchema schema, String viewSql, /** Allows a sub-class to return an extension of {@link ModifiableViewTable} * by overriding this method. */ protected ModifiableViewTable modifiableViewTable(CalcitePrepare.AnalyzeViewResult parsed, - String viewSql, List schemaPath, List viewPath, + String viewSql, List schemaPath, @Nullable List viewPath, CalciteSchema schema) { final JavaTypeFactory typeFactory = (JavaTypeFactory) parsed.typeFactory; final Type elementType = typeFactory.getJavaClass(parsed.rowType); @@ -103,7 +103,7 @@ protected ModifiableViewTable modifiableViewTable(CalcitePrepare.AnalyzeViewResu /** Allows a sub-class to return an extension of {@link ViewTable} by * overriding this method. */ protected ViewTable viewTable(CalcitePrepare.AnalyzeViewResult parsed, - String viewSql, List schemaPath, List viewPath) { + String viewSql, List schemaPath, @Nullable List viewPath) { final JavaTypeFactory typeFactory = (JavaTypeFactory) parsed.typeFactory; final Type elementType = typeFactory.getJavaClass(parsed.rowType); return new ViewTable(elementType, diff --git a/core/src/main/java/org/apache/calcite/server/CalciteServerStatement.java b/core/src/main/java/org/apache/calcite/server/CalciteServerStatement.java index 092d30ea5621..91e6f0865340 100644 --- a/core/src/main/java/org/apache/calcite/server/CalciteServerStatement.java +++ b/core/src/main/java/org/apache/calcite/server/CalciteServerStatement.java @@ -20,6 +20,8 @@ import org.apache.calcite.jdbc.CalciteConnection; import org.apache.calcite.jdbc.CalcitePrepare; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Iterator; /** @@ -34,9 +36,9 @@ public interface CalciteServerStatement { void setSignature(Meta.Signature signature); - Meta.Signature getSignature(); + Meta.@Nullable Signature getSignature(); - Iterator getResultSet(); + @Nullable Iterator getResultSet(); void setResultSet(Iterator resultSet); } diff --git a/core/src/main/java/org/apache/calcite/server/DdlExecutorImpl.java b/core/src/main/java/org/apache/calcite/server/DdlExecutorImpl.java index 79e6881ca6c6..914b98f27b2a 100644 --- a/core/src/main/java/org/apache/calcite/server/DdlExecutorImpl.java +++ b/core/src/main/java/org/apache/calcite/server/DdlExecutorImpl.java @@ -31,7 +31,7 @@ protected DdlExecutorImpl() { /** Dispatches calls to the appropriate method based on the type of the * first argument. */ - @SuppressWarnings("method.invocation.invalid") + @SuppressWarnings({"method.invocation.invalid", "argument.type.incompatible"}) private final ReflectUtil.MethodDispatcher dispatcher = ReflectUtil.createMethodDispatcher(void.class, this, "execute", SqlNode.class, CalcitePrepare.Context.class); diff --git a/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java index ce9123107aec..80d7d9554067 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlAggFunction.java @@ -112,7 +112,7 @@ protected SqlAggFunction( //~ Methods ---------------------------------------------------------------- - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { return clazz.isInstance(this) ? clazz.cast(this) : null; } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlBasicTypeNameSpec.java b/core/src/main/java/org/apache/calcite/sql/SqlBasicTypeNameSpec.java index 4b5abd838b96..8e96d2fb8eed 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlBasicTypeNameSpec.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlBasicTypeNameSpec.java @@ -77,7 +77,7 @@ public class SqlBasicTypeNameSpec extends SqlTypeNameSpec { private int precision; private int scale; - private String charSetName; + private @Nullable String charSetName; /** * Create a basic sql type name specification. @@ -128,7 +128,7 @@ public int getPrecision() { return precision; } - public String getCharSetName() { + public @Nullable String getCharSetName() { return charSetName; } @@ -188,9 +188,6 @@ public String getCharSetName() { @Override public RelDataType deriveType(SqlValidator validator) { final RelDataTypeFactory typeFactory = validator.getTypeFactory(); - if (sqlTypeName == null) { - return null; - } RelDataType type; // NOTE jvs 15-Jan-2009: earlier validation is supposed to // have caught these, which is why it's OK for them diff --git a/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java index 00304536abe8..5e19369eac3c 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java @@ -163,9 +163,6 @@ private RelDataType convertType(SqlValidator validator, SqlCall call, RelDataTyp final SqlMonotonicity mono0 = call.getOperandMonotonicity(0); final SqlMonotonicity mono1 = call.getOperandMonotonicity(1); - if (mono0 == null || mono1 == null) { - return null; - } if (mono1 == SqlMonotonicity.CONSTANT) { if (call.isOperandLiteral(1, false)) { BigDecimal value = call.getOperandLiteralValue(1, BigDecimal.class); 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 e1fae6763cd9..d0fc06db61a5 100755 --- a/core/src/main/java/org/apache/calcite/sql/SqlCall.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlCall.java @@ -83,7 +83,7 @@ public void setOperand(int i, @Nullable SqlNode operand) { * it would trigger too many changes to the current codebase.

* @return the list of call operands, never null, the operands can be null */ - public abstract List getOperandList(); + public abstract List getOperandList(); /** * Returns i-th operand (0-based). @@ -95,7 +95,7 @@ public void setOperand(int i, @Nullable SqlNode operand) { * @return i-th operand (0-based), the result might be null */ @SuppressWarnings("unchecked") - public S operand(int i) { + public S operand(int 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)); diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java index 0e6ca706892c..f3d80aee61ed 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java @@ -170,8 +170,9 @@ private boolean hasAssignment() { /** Returns the operands to a call permuted into the same order as the * formal parameters of the function. */ private List permutedOperands(final SqlCall call) { - final SqlOperandMetadata operandMetadata = - (SqlOperandMetadata) call.getOperator().getOperandTypeChecker(); + final SqlOperandMetadata operandMetadata = requireNonNull( + (SqlOperandMetadata) call.getOperator().getOperandTypeChecker(), + () -> "operandTypeChecker is null for " + call + ", operator " + call.getOperator()); final List paramNames = operandMetadata.paramNames(); final List permuted = new ArrayList<>(); final SqlNameMatcher nameMatcher = @@ -256,7 +257,8 @@ public SqlCall permutedCall() { throw new AssertionError(); } - @Override public @Nullable T getOperandLiteralValue(int ordinal, Class clazz) { + @Override public @Nullable T getOperandLiteralValue(int ordinal, + Class clazz) { final SqlNode node = operand(ordinal); return valueAs(node, clazz); } @@ -277,7 +279,7 @@ public SqlCall permutedCall() { return EnumUtils.evaluate(o2, clazz); } - private @Nullable T valueAs(SqlNode node, Class clazz) { + private @Nullable T valueAs(SqlNode node, Class clazz) { final SqlLiteral literal; switch (node.getKind()) { case ARRAY_VALUE_CONSTRUCTOR: 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 89a7cf00ea8a..56f6bf24aee1 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlDialect.java @@ -535,7 +535,7 @@ public void unparseSqlIntervalLiteral(SqlWriter writer, if (interval.getSign() == -1) { writer.print("-"); } - writer.literal("'" + String.valueOf(literal.getValue()) + "'"); + writer.literal("'" + interval.getIntervalLiteral() + "'"); unparseSqlIntervalQualifier(writer, interval.getIntervalQualifier(), RelDataTypeSystem.DEFAULT); } @@ -874,8 +874,8 @@ public boolean supportsOffsetFetch() { * @see #unparseFetchUsingAnsi(SqlWriter, SqlNode, SqlNode) * @see #unparseFetchUsingLimit(SqlWriter, SqlNode, SqlNode) */ - public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { unparseFetchUsingAnsi(writer, offset, fetch); } 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 8ab4996496ce..817f8079fa4f 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlExplain.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlExplain.java @@ -24,7 +24,6 @@ import java.util.List; -import static java.util.Objects.requireNonNull; /** * A SqlExplain is a node of a parse tree which represents an @@ -121,9 +120,7 @@ public SqlNode getExplicandum() { */ @Pure public SqlExplainLevel getDetailLevel() { - return requireNonNull( - detailLevel.symbolValue(SqlExplainLevel.class), - "detailLevel must not be null"); + return detailLevel.getValueAs(SqlExplainLevel.class); } /** @@ -131,9 +128,7 @@ public SqlExplainLevel getDetailLevel() { */ @Pure public Depth getDepth() { - return requireNonNull( - depth.symbolValue(Depth.class), - "depth must not be null"); + return depth.getValueAs(Depth.class); } /** @@ -165,9 +160,7 @@ public boolean withType() { */ @Pure public SqlExplainFormat getFormat() { - return requireNonNull( - format.symbolValue(SqlExplainFormat.class), - "format must not be null"); + return format.getValueAs(SqlExplainFormat.class); } /** 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 9d3c8339d59f..a48447c33960 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java @@ -217,8 +217,9 @@ public boolean isQuantifierAllowed() { * not allowed. */ protected void validateQuantifier(SqlValidator validator, SqlCall call) { - if ((null != call.getFunctionQuantifier()) && !isQuantifierAllowed()) { - throw validator.newValidationError(call.getFunctionQuantifier(), + SqlLiteral functionQuantifier = call.getFunctionQuantifier(); + if ((null != functionQuantifier) && !isQuantifierAllowed()) { + throw validator.newValidationError(functionQuantifier, RESOURCE.functionQuantifierNotAllowed(call.getOperator().getName())); } } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlGroupedWindowFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlGroupedWindowFunction.java index fe7025cfa7a7..e7b9a3a6d689 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlGroupedWindowFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlGroupedWindowFunction.java @@ -66,7 +66,7 @@ public SqlGroupedWindowFunction(String name, SqlKind kind, @Nullable SqlGroupedWindowFunction groupFunction, SqlReturnTypeInference returnTypeInference, @Nullable SqlOperandTypeInference operandTypeInference, - SqlOperandTypeChecker operandTypeChecker, SqlFunctionCategory category) { + @Nullable SqlOperandTypeChecker operandTypeChecker, SqlFunctionCategory category) { super(name, kind, returnTypeInference, operandTypeInference, operandTypeChecker, category); this.groupFunction = groupFunction; @@ -77,7 +77,7 @@ public SqlGroupedWindowFunction(String name, SqlKind kind, @Deprecated // to be removed before 2.0 public SqlGroupedWindowFunction(String name, SqlKind kind, @Nullable SqlGroupedWindowFunction groupFunction, - SqlOperandTypeChecker operandTypeChecker) { + @Nullable SqlOperandTypeChecker operandTypeChecker) { this(name, kind, groupFunction, ReturnTypes.ARG0, null, operandTypeChecker, SqlFunctionCategory.SYSTEM); } @@ -85,7 +85,7 @@ public SqlGroupedWindowFunction(String name, SqlKind kind, @Deprecated // to be removed before 2.0 public SqlGroupedWindowFunction(SqlKind kind, @Nullable SqlGroupedWindowFunction groupFunction, - SqlOperandTypeChecker operandTypeChecker) { + @Nullable SqlOperandTypeChecker operandTypeChecker) { this(kind.name(), kind, groupFunction, ReturnTypes.ARG0, null, operandTypeChecker, SqlFunctionCategory.SYSTEM); } 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 afb082b11d7a..b70f2ef41e4c 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlJdbcFunctionCall.java @@ -765,7 +765,7 @@ private JdbcToInternalLookupTable() { assert typeOperand.getKind() == SqlKind.LITERAL; SqlJdbcDataTypeName jdbcType = ((SqlLiteral) typeOperand) - .symbolValue(SqlJdbcDataTypeName.class); + .getValueAs(SqlJdbcDataTypeName.class); return super.createCall(pos, operands[0], jdbcType.createDataType(typeOperand.pos)); } 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 35ac35e3690c..5f6a0b82f1b5 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlJoin.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlJoin.java @@ -71,8 +71,8 @@ public SqlJoin(SqlParserPos pos, SqlNode left, SqlLiteral natural, this.condition = condition; Preconditions.checkArgument(natural.getTypeName() == SqlTypeName.BOOLEAN); - requireNonNull(conditionType.symbolValue(JoinConditionType.class)); - requireNonNull(joinType.symbolValue(JoinType.class)); + conditionType.getValueAs(JoinConditionType.class); + joinType.getValueAs(JoinType.class); } //~ Methods ---------------------------------------------------------------- @@ -123,9 +123,7 @@ public SqlJoin(SqlParserPos pos, SqlNode left, SqlLiteral natural, /** Returns a {@link JoinConditionType}, never null. */ public final JoinConditionType getConditionType() { - return requireNonNull( - conditionType.symbolValue(JoinConditionType.class), - "conditionType must not be null"); + return conditionType.getValueAs(JoinConditionType.class); } public SqlLiteral getConditionTypeNode() { @@ -134,9 +132,7 @@ public SqlLiteral getConditionTypeNode() { /** Returns a {@link JoinType}, never null. */ public final JoinType getJoinType() { - return requireNonNull( - joinType.symbolValue(JoinType.class), - "joinType must not be null"); + return joinType.getValueAs(JoinType.class); } public SqlLiteral getJoinTypeNode() { 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 8398605e176f..de89bdd2f201 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java @@ -279,7 +279,7 @@ public static boolean valueMatchesType( * * @throws AssertionError if the value type is not supported */ - public T getValueAs(Class clazz) { + public T getValueAs(Class clazz) { Object value = this.value; if (clazz.isInstance(value)) { return clazz.cast(value); @@ -301,7 +301,7 @@ public T getValueAs(Class clazz) { break; case DECIMAL: if (clazz == Long.class) { - return clazz.cast(((BigDecimal) value).unscaledValue().longValue()); + return clazz.cast(((BigDecimal) value).longValueExact()); } // fall through case BIGINT: @@ -312,13 +312,13 @@ public T getValueAs(Class clazz) { case REAL: case FLOAT: if (clazz == Long.class) { - return clazz.cast(((BigDecimal) value).longValue()); + return clazz.cast(((BigDecimal) value).longValueExact()); } else if (clazz == Integer.class) { - return clazz.cast(((BigDecimal) value).intValue()); + return clazz.cast(((BigDecimal) value).intValueExact()); } else if (clazz == Short.class) { - return clazz.cast(((BigDecimal) value).shortValue()); + return clazz.cast(((BigDecimal) value).shortValueExact()); } else if (clazz == Byte.class) { - return clazz.cast(((BigDecimal) value).byteValue()); + return clazz.cast(((BigDecimal) value).byteValueExact()); } else if (clazz == Double.class) { return clazz.cast(((BigDecimal) value).doubleValue()); } else if (clazz == Float.class) { 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 1ace09c0e50e..8c72d1d7974b 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java @@ -85,7 +85,7 @@ public SqlNodeList(SqlParserPos pos) { * list. The list is copied, but the nodes in it are not. */ public SqlNodeList( - Collection collection, + Collection collection, SqlParserPos pos) { super(pos); list = new ArrayList<>(collection); @@ -94,12 +94,12 @@ public SqlNodeList( //~ Methods ---------------------------------------------------------------- @SuppressWarnings("return.type.incompatible") - @Override public Iterator iterator() { + @Override public Iterator iterator() { return list.iterator(); } @SuppressWarnings("return.type.incompatible") - public List getList() { + public List getList() { return list; } @@ -112,11 +112,11 @@ public void add(@Nullable SqlNode node) { return new SqlNodeList(list, pos); } - public SqlNode get(int n) { + public /*Nullable*/ SqlNode get(int n) { return castNonNull(list.get(n)); } - public SqlNode set(int n, SqlNode node) { + public SqlNode set(int n, @Nullable SqlNode node) { return castNonNull(list.set(n, node)); } @@ -184,7 +184,7 @@ void andOrList(SqlWriter writer, SqlBinaryOperator sepOp) { } @SuppressWarnings("return.type.incompatible") - public SqlNode[] toArray() { + public /*Nullable*/ SqlNode[] toArray() { return list.toArray(new SqlNode[0]); } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlNumericLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlNumericLiteral.java index e88a2241b1ac..8cf6bd1ff07f 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlNumericLiteral.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlNumericLiteral.java @@ -26,7 +26,8 @@ import org.checkerframework.dataflow.qual.Pure; import java.math.BigDecimal; -import java.util.Objects; + +import static java.util.Objects.requireNonNull; /** * A numeric SQL literal. @@ -58,7 +59,7 @@ protected SqlNumericLiteral( //~ Methods ---------------------------------------------------------------- private BigDecimal getValueNonNull() { - return (BigDecimal) Objects.requireNonNull(value, "value"); + return (BigDecimal) requireNonNull(value, "value"); } public @Nullable Integer getPrec() { @@ -96,7 +97,7 @@ public boolean isExact() { @Override public RelDataType createSqlType(RelDataTypeFactory typeFactory) { if (isExact) { - int scaleValue = scale.intValue(); + int scaleValue = requireNonNull(scale, "scale"); if (0 == scaleValue) { BigDecimal bd = getValueNonNull(); SqlTypeName result; @@ -112,7 +113,7 @@ public boolean isExact() { // else we have a decimal return typeFactory.createSqlType( SqlTypeName.DECIMAL, - prec.intValue(), + requireNonNull(prec, "prec"), scaleValue); } @@ -122,6 +123,6 @@ public boolean isExact() { } public boolean isInteger() { - return 0 == scale.intValue(); + return scale != null && 0 == scale.intValue(); } } 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 b275c9f13c14..2d56945e4183 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java @@ -295,7 +295,7 @@ public final SqlCall createCall( */ public final SqlCall createCall( SqlParserPos pos, - List operandList) { + List operandList) { return createCall( null, pos, diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java b/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java index 28505602457f..1693e89cd5fb 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java @@ -133,7 +133,7 @@ public int getIntLiteralOperand(int ordinal) { * * @return value of operand */ - public @Nullable T getOperandLiteralValue(int ordinal, Class clazz) { + public @Nullable T getOperandLiteralValue(int ordinal, Class clazz) { throw new UnsupportedOperationException(); } diff --git a/core/src/main/java/org/apache/calcite/sql/SqlPivot.java b/core/src/main/java/org/apache/calcite/sql/SqlPivot.java index dce7dec5c855..b707c6274183 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlPivot.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlPivot.java @@ -26,13 +26,14 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.function.BiConsumer; import java.util.stream.Collectors; -import javax.annotation.Nonnull; /** * Parse tree node that represents a PIVOT applied to a table reference @@ -66,7 +67,7 @@ public SqlPivot(SqlParserPos pos, SqlNode query, SqlNodeList aggList, //~ Methods ---------------------------------------------------------------- - @Override @Nonnull public SqlOperator getOperator() { + @Override public SqlOperator getOperator() { return OPERATOR; } @@ -74,7 +75,8 @@ public SqlPivot(SqlParserPos pos, SqlNode query, SqlNodeList aggList, return ImmutableNullableList.of(query, aggList, axisList, inList); } - @Override public void setOperand(int i, SqlNode operand) { + @SuppressWarnings("nullness") + @Override public void setOperand(int i, @Nullable SqlNode operand) { // Only 'query' is mutable. (It is required for validation.) switch (i) { case 0: @@ -127,7 +129,7 @@ private static SqlNode strip(SqlNode e) { /** Returns the aggregate list as (alias, call) pairs. * If there is no 'AS', alias is null. */ - public void forEachAgg(BiConsumer consumer) { + public void forEachAgg(BiConsumer<@Nullable String, SqlNode> consumer) { for (SqlNode agg : aggList) { final SqlNode call = SqlUtil.stripAs(agg); final String alias = SqlValidatorUtil.getAlias(agg, -1); diff --git a/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java index ae1e2a478176..a7e2a144b1ca 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java @@ -28,6 +28,9 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static org.apache.calcite.sql.type.NonNullableAccessors.getCharset; +import static org.apache.calcite.sql.type.NonNullableAccessors.getCollation; + /** * A unary operator. */ @@ -75,14 +78,12 @@ public SqlPrefixOperator( throw new AssertionError("operand's type should have been derived"); } if (SqlTypeUtil.inCharFamily(operandType)) { - SqlCollation collation = operandType.getCollation(); - assert null != collation - : "An implicit or explicit collation should have been set"; + SqlCollation collation = getCollation(operandType); type = validator.getTypeFactory() .createTypeWithCharsetAndCollation( type, - type.getCharset(), + getCharset(type), collation); } } @@ -91,8 +92,7 @@ public SqlPrefixOperator( @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) { if (getName().equals("-")) { - SqlMonotonicity monotonicity = call.getOperandMonotonicity(0); - return monotonicity == null ? null : monotonicity.reverse(); + return call.getOperandMonotonicity(0).reverse(); } return super.getMonotonicity(call); diff --git a/core/src/main/java/org/apache/calcite/sql/SqlRowTypeNameSpec.java b/core/src/main/java/org/apache/calcite/sql/SqlRowTypeNameSpec.java index b0b6ce1ca2b0..c6f22e4db799 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlRowTypeNameSpec.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlRowTypeNameSpec.java @@ -92,7 +92,8 @@ public int getArity() { writer.sep(",", false); p.left.unparse(writer, 0, 0); p.right.unparse(writer, leftPrec, rightPrec); - if (p.right.getNullable() != null && p.right.getNullable()) { + Boolean isNullable = p.right.getNullable(); + if (isNullable != null && isNullable) { // Row fields default is not nullable. writer.print("NULL"); } 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 def7469256c8..f5ddbff5bc87 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java @@ -165,7 +165,7 @@ public static SqlNodeList toNodeList(SqlNode[] operands) { * */ public static boolean isNullLiteral( - SqlNode node, + @Nullable SqlNode node, boolean allowCast) { if (node instanceof SqlLiteral) { SqlLiteral literal = (SqlLiteral) node; @@ -178,7 +178,7 @@ public static boolean isNullLiteral( return false; } } - if (allowCast) { + if (allowCast && node != null) { if (node.getKind() == SqlKind.CAST) { SqlCall call = (SqlCall) node; if (isNullLiteral(call.operand(0), false)) { diff --git a/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisor.java b/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisor.java index e4082d22ea2c..323240af0b81 100644 --- a/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisor.java +++ b/core/src/main/java/org/apache/calcite/sql/advise/SqlAdvisor.java @@ -483,6 +483,9 @@ public boolean isValid(String sql) { sqlNode = collectParserError(sql, errorList); if (!errorList.isEmpty()) { return errorList; + } else if (sqlNode == null) { + throw new IllegalStateException("collectParserError returned null (sql is not valid)" + + ", however, the resulting errorList is empty. sql=" + sql); } try { validator.validate(sqlNode); @@ -542,7 +545,7 @@ private Set getReservedAndKeyWordsSet() { @EnsuresNonNull({"reservedWordsSet", "reservedWordsList"}) private void ensureReservedAndKeyWords() { - if (reservedWordsSet != null) { + if (reservedWordsSet != null && reservedWordsList != null) { return; } Collection c = SqlAbstractParserImpl.getSql92ReservedWords(); @@ -594,7 +597,7 @@ protected SqlNode parseQuery(String sql) throws SqlParseException { * @return {@link SqlNode } that is root of the parse tree, null if the sql * is not valid */ - protected SqlNode collectParserError( + protected @Nullable SqlNode collectParserError( String sql, List errorList) { try { @@ -619,7 +622,7 @@ public static class ValidateErrorInfo { private int startColumnNum; private int endLineNum; private int endColumnNum; - private String errorMsg; + private @Nullable String errorMsg; /** * Creates a new ValidateErrorInfo with the position coordinates and an @@ -636,7 +639,7 @@ public ValidateErrorInfo( int startColumnNum, int endLineNum, int endColumnNum, - String errorMsg) { + @Nullable String errorMsg) { this.startLineNum = startLineNum; this.startColumnNum = startColumnNum; this.endLineNum = endLineNum; @@ -655,7 +658,8 @@ public ValidateErrorInfo( this.startColumnNum = e.getPosColumn(); this.endLineNum = e.getEndPosLine(); this.endColumnNum = e.getEndPosColumn(); - this.errorMsg = e.getCause().getMessage(); + Throwable cause = e.getCause(); + this.errorMsg = (cause == null ? e : cause).getMessage(); } /** @@ -667,7 +671,7 @@ public ValidateErrorInfo( */ public ValidateErrorInfo( SqlParserPos pos, - String errorMsg) { + @Nullable String errorMsg) { this.startLineNum = pos.getLineNum(); this.startColumnNum = pos.getColumnNum(); this.endLineNum = pos.getEndLineNum(); @@ -696,7 +700,7 @@ public int getEndColumnNum() { } /** Returns the error message. */ - public String getMessage() { + public @Nullable String getMessage() { return errorMsg; } } diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java index 7ee43fbd319a..bdeedc075cb9 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java @@ -124,8 +124,8 @@ public BigQuerySqlDialect(SqlDialect.Context context) { .withCharLiteralStyles(Lex.BIG_QUERY.charLiteralStyles); } - @Override public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { unparseFetchUsingLimit(writer, offset, fetch); } @@ -186,13 +186,12 @@ public BigQuerySqlDialect(SqlDialect.Context context) { if (interval.getSign() == -1) { writer.print("-"); } - Long intervalValueInLong; try { - intervalValueInLong = Long.parseLong(literal.getValue().toString()); + Long.parseLong(interval.getIntervalLiteral()); } catch (NumberFormatException e) { throw new RuntimeException("Only INT64 is supported as the interval value for BigQuery."); } - writer.literal(intervalValueInLong.toString()); + writer.literal(interval.getIntervalLiteral()); unparseSqlIntervalQualifier(writer, interval.getIntervalQualifier(), RelDataTypeSystem.DEFAULT); } diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/ClickHouseSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/ClickHouseSqlDialect.java index fd9e4e7cad9d..700660ae4764 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/ClickHouseSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/ClickHouseSqlDialect.java @@ -130,8 +130,8 @@ private SqlDataTypeSpec createSqlDataTypeSpecByName(String typeAlias, SqlTypeNam writer.literal(toFunc + "('" + literal.toFormattedString() + "')"); } - @Override public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { Preconditions.checkArgument(fetch != null); writer.newlineAndIndent(); @@ -193,7 +193,7 @@ private SqlDataTypeSpec createSqlDataTypeSpecByName(String typeAlias, SqlTypeNam */ private void unparseFloor(SqlWriter writer, SqlCall call) { final SqlLiteral timeUnitNode = call.operand(1); - TimeUnitRange unit = (TimeUnitRange) timeUnitNode.getValue(); + TimeUnitRange unit = timeUnitNode.getValueAs(TimeUnitRange.class); String funName; switch (unit) { diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/Db2SqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/Db2SqlDialect.java index 9dbbda032a2a..fb335e8aa5c8 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/Db2SqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/Db2SqlDialect.java @@ -88,7 +88,7 @@ public Db2SqlDialect(Context context) { if (interval.getSign() == -1) { writer.print("-"); } - writer.literal(literal.getValue().toString()); + writer.literal(interval.getIntervalLiteral()); unparseSqlIntervalQualifier(writer, interval.getIntervalQualifier(), RelDataTypeSystem.DEFAULT); } diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/HiveSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/HiveSqlDialect.java index 80a65cd9012e..3aba1e51ead2 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/HiveSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/HiveSqlDialect.java @@ -64,8 +64,8 @@ public HiveSqlDialect(Context context) { return false; } - @Override public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { unparseFetchUsingLimit(writer, offset, fetch); } diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/HsqldbSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/HsqldbSqlDialect.java index 6b105fc9c945..1c0965c49cd9 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/HsqldbSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/HsqldbSqlDialect.java @@ -29,6 +29,8 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.parser.SqlParserPos; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * A SqlDialect implementation for the Hsqldb database. */ @@ -74,8 +76,8 @@ public HsqldbSqlDialect(Context context) { } } - @Override public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { unparseFetchUsingLimit(writer, offset, fetch); } 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 e56c9f9d0acd..f33d00e049ad 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 @@ -112,8 +112,8 @@ public MssqlSqlDialect(Context context) { } } - @Override public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { if (!top) { super.unparseOffsetFetch(writer, offset, fetch); } @@ -185,7 +185,7 @@ public MssqlSqlDialect(Context context) { */ private void unparseFloor(SqlWriter writer, SqlCall call) { SqlLiteral node = call.operand(1); - TimeUnitRange unit = (TimeUnitRange) node.getValue(); + TimeUnitRange unit = node.getValueAs(TimeUnitRange.class); switch (unit) { case YEAR: @@ -279,7 +279,7 @@ private void unparseSqlIntervalLiteralMssql( if (interval.getSign() * sign == -1) { writer.print("-"); } - writer.literal(literal.getValue().toString()); + writer.literal(interval.getIntervalLiteral()); } private void unparseFloorWithUnit(SqlWriter writer, SqlCall call, int charLen, diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/MysqlSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/MysqlSqlDialect.java index 0809fb951ad9..9b1ec16a88a4 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/MysqlSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/MysqlSqlDialect.java @@ -106,8 +106,8 @@ public MysqlSqlDialect(Context context) { return false; } - @Override public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { unparseFetchUsingLimit(writer, offset, fetch); } @@ -236,7 +236,7 @@ public MysqlSqlDialect(Context context) { */ private void unparseFloor(SqlWriter writer, SqlCall call) { SqlLiteral node = call.operand(1); - TimeUnitRange unit = (TimeUnitRange) node.getValue(); + TimeUnitRange unit = node.getValueAs(TimeUnitRange.class); if (unit == TimeUnitRange.WEEK) { writer.print("STR_TO_DATE"); diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/PrestoSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/PrestoSqlDialect.java index 1baa0a840351..8bee34847edd 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/PrestoSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/PrestoSqlDialect.java @@ -60,8 +60,8 @@ public PrestoSqlDialect(Context context) { return true; } - @Override public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { unparseUsingLimit(writer, offset, fetch); } diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/RedshiftSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/RedshiftSqlDialect.java index 6a9364b28879..586d3ae75bd9 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/RedshiftSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/RedshiftSqlDialect.java @@ -21,6 +21,8 @@ import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlWriter; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * A SqlDialect implementation for the Redshift database. */ @@ -39,8 +41,8 @@ public RedshiftSqlDialect(Context context) { super(context); } - @Override public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { unparseFetchUsingLimit(writer, offset, fetch); } } diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/SparkSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/SparkSqlDialect.java index 9423e9c94002..8fc37c244da4 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/SparkSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/SparkSqlDialect.java @@ -32,6 +32,8 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.sql.type.ReturnTypes; +import org.checkerframework.checker.nullness.qual.Nullable; + import static org.apache.calcite.util.RelToSqlConverterUtil.unparseHiveTrim; /** @@ -80,8 +82,8 @@ public SparkSqlDialect(SqlDialect.Context context) { return true; } - @Override public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { unparseFetchUsingLimit(writer, offset, fetch); } 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 b98932a33aac..8b42498685f6 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 @@ -36,8 +36,8 @@ public SybaseSqlDialect(Context context) { super(context); } - @Override public void unparseOffsetFetch(SqlWriter writer, SqlNode offset, - SqlNode fetch) { + @Override public void unparseOffsetFetch(SqlWriter writer, @Nullable SqlNode offset, + @Nullable SqlNode fetch) { // No-op; see unparseTopN. // Sybase uses "SELECT TOP (n)" rather than "FETCH NEXT n ROWS". } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlArrayValueConstructor.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlArrayValueConstructor.java index 78b144323002..e291c4121194 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlArrayValueConstructor.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlArrayValueConstructor.java @@ -21,6 +21,8 @@ import org.apache.calcite.sql.SqlOperatorBinding; import org.apache.calcite.sql.type.SqlTypeUtil; +import static java.util.Objects.requireNonNull; + /** * Definition of the SQL:2003 standard ARRAY constructor, ARRAY * [<expr>, ...]. @@ -35,9 +37,7 @@ public SqlArrayValueConstructor() { getComponentType( opBinding.getTypeFactory(), opBinding.collectOperandTypes()); - if (null == type) { - return null; - } + requireNonNull(type, "inferred array element type"); return SqlTypeUtil.createArrayType( opBinding.getTypeFactory(), type, false); } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java index 54b60cf08ebd..685a12d41414 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java @@ -39,6 +39,8 @@ import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * Defines the BETWEEN operator. * @@ -125,8 +127,9 @@ public boolean isNegated() { new ExplicitOperatorBinding( opBinding, opBinding.collectOperandTypes()); - return ReturnTypes.BOOLEAN_NULLABLE.inferReturnType( + RelDataType type = ReturnTypes.BOOLEAN_NULLABLE.inferReturnType( newOpBinding); + return requireNonNull(type, "inferred BETWEEN element type"); } @Override public String getSignatureTemplate(final int operandsCount) { diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlBitOpAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlBitOpAggFunction.java index 96abcca114cb..ad9629d84ad3 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlBitOpAggFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlBitOpAggFunction.java @@ -56,7 +56,7 @@ public SqlBitOpAggFunction(SqlKind kind) { || kind == SqlKind.BIT_XOR); } - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { if (clazz == SqlSplittableAggFunction.class) { return clazz.cast(SqlSplittableAggFunction.SelfSplitter.INSTANCE); } 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 b39425176470..f062d4737dbe 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 @@ -104,6 +104,7 @@ public static SqlCase createSwitched(SqlParserPos pos, @Nullable SqlNode value, return SqlStdOperatorTable.CASE; } + @SuppressWarnings("nullness") @Override public List getOperandList() { return UnmodifiableArrayList.of(value, whenList, thenList, 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 1c16e4935663..dd6a1c0d3d32 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 @@ -253,7 +253,8 @@ private RelDataType inferTypeFromValidator( } } - SqlNode elseOp = caseCall.getElseOperand(); + SqlNode elseOp = requireNonNull(caseCall.getElseOperand(), + () -> "elseOperand for " + caseCall); argTypes.add( SqlTypeUtil.deriveType(callBinding, elseOp)); if (SqlUtil.isNullLiteral(elseOp, false)) { @@ -283,6 +284,7 @@ private RelDataType inferTypeFromValidator( } final SqlValidatorImpl validator = (SqlValidatorImpl) callBinding.getValidator(); + requireNonNull(ret, () -> "return type for " + callBinding); for (SqlNode node : nullList) { validator.setValidatedNodeType(node, ret); } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java index 5d6e49eee70d..ce45bf7e24fe 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java @@ -25,7 +25,6 @@ import org.apache.calcite.sql.SqlFunctionCategory; import org.apache.calcite.sql.SqlIntervalQualifier; import org.apache.calcite.sql.SqlKind; -import org.apache.calcite.sql.SqlLiteral; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlOperandCountRange; import org.apache.calcite.sql.SqlOperatorBinding; @@ -109,8 +108,7 @@ public SqlCastFunction() { // dynamic parameters and null constants need their types assigned // to them using the type they are casted to. - if (((operand0 instanceof SqlLiteral) - && (((SqlLiteral) operand0).getValue() == null)) + if (SqlUtil.isNullLiteral(operand0, false) || (operand0 instanceof SqlDynamicParam)) { final SqlValidatorImpl validator = (SqlValidatorImpl) callBinding.getValidator(); diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlConvertFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlConvertFunction.java index 4720a5c88002..9f9a6da01637 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlConvertFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlConvertFunction.java @@ -22,6 +22,7 @@ import org.apache.calcite.sql.SqlKind; import org.apache.calcite.sql.SqlWriter; + /** * Common base for the CONVERT and TRANSLATE * functions. @@ -60,7 +61,6 @@ protected SqlConvertFunction(String name) { default: break; } - assert false; - return null; + throw new IllegalStateException("operandsCount should be 2, got " + operandsCount); } } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java index 4f865b8a986c..763b291c689f 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCountAggFunction.java @@ -91,7 +91,7 @@ public SqlCountAggFunction(String name, return super.deriveType(validator, scope, call); } - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { if (clazz == SqlSplittableAggFunction.class) { return clazz.cast(SqlSplittableAggFunction.CountSplitter.INSTANCE); } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java index a580f5d0e4c1..b1824cb37540 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java @@ -28,6 +28,8 @@ import org.apache.calcite.sql.validate.SqlMonotonicity; import org.apache.calcite.util.Util; +import static java.util.Objects.requireNonNull; + /** * The SQL EXTRACT operator. Extracts a specified field value from * a DATETIME or an INTERVAL. E.g.
@@ -65,10 +67,10 @@ public SqlExtractFunction() { } @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) { - switch (call.getOperandLiteralValue(0, TimeUnitRange.class)) { + TimeUnitRange value = call.getOperandLiteralValue(0, TimeUnitRange.class); + switch (requireNonNull(value, "value for " + call)) { case YEAR: - SqlMonotonicity monotonicity = call.getOperandMonotonicity(1); - return monotonicity == null ? null : monotonicity.unstrict(); + return call.getOperandMonotonicity(1).unstrict(); default: return SqlMonotonicity.NOT_MONOTONIC; } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java index 7a0677362bf0..d1f453116362 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java @@ -55,8 +55,7 @@ public SqlFloorFunction(SqlKind kind) { @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) { // Monotonic iff its first argument is, but not strict. - SqlMonotonicity monotonicity = call.getOperandMonotonicity(0); - return monotonicity == null ? null : monotonicity.unstrict(); + return call.getOperandMonotonicity(0).unstrict(); } @Override public void unparse(SqlWriter writer, SqlCall call, int leftPrec, 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 7ed80aa6c838..08206aabeb50 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 @@ -103,7 +103,7 @@ public static class GridTable implements ScannableTable { .build(); } - @Override public Enumerable scan(DataContext root) { + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { if (geom != null && deltaX != null && deltaY != null) { final Geometry geometry = geom.g(); final Envelope envelope = new Envelope(); diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonValueFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonValueFunction.java index 8e5b1e1fdfde..922324a469c2 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonValueFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlJsonValueFunction.java @@ -70,7 +70,7 @@ private static RelDataType getDefaultType(SqlOperatorBinding opBinding) { * Returns new operand list with type specification removed. */ public static List removeTypeSpecOperands(SqlCall call) { - SqlNode[] operands = call.getOperandList().toArray(SqlNode.EMPTY_ARRAY); + SqlNode[] operands = call.getOperandList().toArray(new SqlNode[0]); if (hasExplicitTypeSpec(operands)) { operands[2] = null; operands[3] = null; diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java index d57849614364..0c92db7f95ff 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java @@ -75,7 +75,7 @@ private SqlLibraryOperators() { } final RelDataTypeFactory typeFactory = opBinding.getTypeFactory(); RelDataType type = typeFactory.leastRestrictive(list); - if (opBinding.getOperandCount() % 2 == 1) { + if (type != null && opBinding.getOperandCount() % 2 == 1) { type = typeFactory.createTypeWithNullability(type, true); } return type; diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java index 399d38f21429..11cf63cbdd75 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLiteralChainOperator.java @@ -46,6 +46,7 @@ import static org.apache.calcite.linq4j.Nullness.castNonNull; import static org.apache.calcite.util.Static.RESOURCE; + /** * Internal operator, by which the parser represents a continued string literal. * @@ -178,7 +179,7 @@ private boolean argTypesValid(SqlCallBinding callBinding) { } else { // print without prefix if (rand.getTypeName() == SqlTypeName.BINARY) { - BitString bs = (BitString) rand.getValue(); + BitString bs = rand.getValueAs(BitString.class); writer.literal("'" + bs.toHexString() + "'"); } else { writer.literal("'" + rand.toValue() + "'"); diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java index 61300d1b910a..e5f2c9318fd4 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMapValueConstructor.java @@ -25,10 +25,14 @@ import org.apache.calcite.util.Pair; import org.apache.calcite.util.Util; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * Definition of the MAP constructor, * MAP [<key>, <value>, ...]. @@ -41,16 +45,13 @@ public SqlMapValueConstructor() { } @Override public RelDataType inferReturnType(SqlOperatorBinding opBinding) { - Pair type = + Pair<@Nullable RelDataType, @Nullable RelDataType> type = getComponentTypes( opBinding.getTypeFactory(), opBinding.collectOperandTypes()); - if (null == type) { - return null; - } return SqlTypeUtil.createMapType( opBinding.getTypeFactory(), - type.left, - type.right, + requireNonNull(type.left, "inferred key type"), + requireNonNull(type.right, "inferred value type"), false); } @@ -64,7 +65,7 @@ public SqlMapValueConstructor() { if (argTypes.size() % 2 > 0) { throw callBinding.newValidationError(RESOURCE.mapRequiresEvenArgCount()); } - final Pair componentType = + final Pair<@Nullable RelDataType, @Nullable RelDataType> componentType = getComponentTypes( callBinding.getTypeFactory(), argTypes); if (null == componentType.left || null == componentType.right) { @@ -76,7 +77,7 @@ public SqlMapValueConstructor() { return true; } - private Pair getComponentTypes( + private Pair<@Nullable RelDataType, @Nullable RelDataType> getComponentTypes( RelDataTypeFactory typeFactory, List argTypes) { return Pair.of( diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java index b05f631d1a7a..39ec5d605009 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMinMaxAggFunction.java @@ -145,7 +145,7 @@ public int getMinMaxKind() { } } - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { if (clazz == SqlSplittableAggFunction.class) { return clazz.cast(SqlSplittableAggFunction.SelfSplitter.INSTANCE); } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java index 72a67073b889..9ec3e8a9929c 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java @@ -58,10 +58,6 @@ public SqlMonotonicBinaryOperator( final SqlMonotonicity mono0 = call.getOperandMonotonicity(0); final SqlMonotonicity mono1 = call.getOperandMonotonicity(1); - // unknown unknown --> unknown - if (mono0 == null || mono1 == null) { - return null; - } // constant constant --> constant if ((mono1 == SqlMonotonicity.CONSTANT) && (mono0 == SqlMonotonicity.CONSTANT)) { diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java index 82e4141e9cd1..0d77cb8af29d 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetQueryConstructor.java @@ -32,10 +32,14 @@ import org.apache.calcite.sql.validate.SqlValidatorNamespace; import org.apache.calcite.sql.validate.SqlValidatorScope; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * Definition of the SQL:2003 standard MULTISET query constructor, * MULTISET (<query>). @@ -67,16 +71,14 @@ protected SqlMultisetQueryConstructor(String name, SqlKind kind) { getComponentType( opBinding.getTypeFactory(), opBinding.collectOperandTypes()); - if (null == type) { - return null; - } + requireNonNull(type, "inferred multiset query element type"); return SqlTypeUtil.createMultisetType( opBinding.getTypeFactory(), type, false); } - private RelDataType getComponentType( + private @Nullable RelDataType getComponentType( RelDataTypeFactory typeFactory, List argTypes) { return typeFactory.leastRestrictive(argTypes); diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java index 367ffce3bd0a..ccf681f3ee1c 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMultisetValueConstructor.java @@ -36,6 +36,8 @@ import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * Definition of the SQL:2003 standard MULTISET constructor, MULTISET * [<expr>, ...]. @@ -69,9 +71,7 @@ protected SqlMultisetValueConstructor(String name, SqlKind kind) { getComponentType( opBinding.getTypeFactory(), opBinding.collectOperandTypes()); - if (null == type) { - return null; - } + requireNonNull(type, "inferred multiset value"); return SqlTypeUtil.createMultisetType( opBinding.getTypeFactory(), type, diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlOverlayFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlOverlayFunction.java index f3f95c1fb374..71192cfb6619 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlOverlayFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlOverlayFunction.java @@ -75,9 +75,7 @@ public SqlOverlayFunction() { case 4: return "{0}({1} PLACING {2} FROM {3} FOR {4})"; default: - break; + throw new IllegalArgumentException("operandsCount shuld be 3 or 4, got " + operandsCount); } - assert false; - return null; } } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java index 8daf2e80f45e..7cec5f2eaed1 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlSumAggFunction.java @@ -79,7 +79,7 @@ public RelDataType getType() { return type; } - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { if (clazz == SqlSplittableAggFunction.class) { return clazz.cast(SqlSplittableAggFunction.SumSplitter.INSTANCE); } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java index d01758727435..0b3ce66be351 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlSumEmptyIsZeroAggFunction.java @@ -70,7 +70,7 @@ public SqlSumEmptyIsZeroAggFunction() { typeFactory.createSqlType(SqlTypeName.ANY), true); } - @Override public @Nullable T unwrap(Class clazz) { + @Override public @Nullable T unwrap(Class clazz) { if (clazz == SqlSplittableAggFunction.class) { return clazz.cast(SqlSplittableAggFunction.Sum0Splitter.INSTANCE); } 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 3d1ac243bba8..ecb793c7829a 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 @@ -31,6 +31,7 @@ import java.util.List; import java.util.Objects; +import static org.apache.calcite.linq4j.Nullness.castNonNull; import static org.apache.calcite.util.Static.RESOURCE; /** @@ -199,7 +200,8 @@ private static List toPos(final SqlNode[] nodes) { private static Iterable<@PolyNull SqlParserPos> toPos( Iterable nodes) { - return Util.transform(nodes, node -> node == null ? null : node.getParserPosition()); + return Util.transform(nodes, + node -> node == null ? castNonNull(null) : node.getParserPosition()); } /** 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 0effd8c03541..14cdd10e0497 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 @@ -50,6 +50,8 @@ import java.util.Set; import java.util.function.Consumer; +import static java.util.Objects.requireNonNull; + /** * Pretty printer for SQL statements. * @@ -281,9 +283,9 @@ public class SqlPrettyWriter implements SqlWriter { @SuppressWarnings("method.invocation.invalid") private SqlPrettyWriter(SqlWriterConfig config, StringBuilder buf, @SuppressWarnings("unused") boolean ignore) { - this.buf = Objects.requireNonNull(buf); - this.dialect = Objects.requireNonNull(config.dialect()); - this.config = Objects.requireNonNull(config); + this.buf = requireNonNull(buf); + this.dialect = requireNonNull(config.dialect()); + this.config = requireNonNull(config); lineStart = 0; reset(); } @@ -292,7 +294,7 @@ private SqlPrettyWriter(SqlWriterConfig config, * and a given buffer to write to. */ public SqlPrettyWriter(SqlWriterConfig config, StringBuilder buf) { - this(config, Objects.requireNonNull(buf), false); + this(config, requireNonNull(buf), false); } /** Creates a writer with the given configuration and dialect, @@ -301,14 +303,14 @@ public SqlPrettyWriter( SqlDialect dialect, SqlWriterConfig config, StringBuilder buf) { - this(config.withDialect(Objects.requireNonNull(dialect)), buf); + this(config.withDialect(requireNonNull(dialect)), buf); } /** Creates a writer with the given configuration * and a private print writer. */ @Deprecated public SqlPrettyWriter(SqlDialect dialect, SqlWriterConfig config) { - this(config.withDialect(Objects.requireNonNull(dialect))); + this(config.withDialect(requireNonNull(dialect))); } @Deprecated @@ -317,7 +319,7 @@ public SqlPrettyWriter( boolean alwaysUseParentheses, PrintWriter pw) { // NOTE that 'pw' is ignored; there is no place for it in the new API - this(config().withDialect(Objects.requireNonNull(dialect)) + this(config().withDialect(requireNonNull(dialect)) .withAlwaysUseParentheses(alwaysUseParentheses)); } @@ -325,7 +327,7 @@ public SqlPrettyWriter( public SqlPrettyWriter( SqlDialect dialect, boolean alwaysUseParentheses) { - this(config().withDialect(Objects.requireNonNull(dialect)) + this(config().withDialect(requireNonNull(dialect)) .withAlwaysUseParentheses(alwaysUseParentheses)); } @@ -333,7 +335,7 @@ public SqlPrettyWriter( * and a private print writer. */ @Deprecated public SqlPrettyWriter(SqlDialect dialect) { - this(config().withDialect(Objects.requireNonNull(dialect))); + this(config().withDialect(requireNonNull(dialect))); } /** Creates a writer with the given configuration, @@ -1098,7 +1100,7 @@ public void setLineLength(int lineLength) { this.config = config.withLineLength(lineLength); } - public void setFormatOptions(SqlFormatOptions options) { + public void setFormatOptions(@Nullable SqlFormatOptions options) { if (options == null) { return; } @@ -1414,7 +1416,10 @@ private static String stripPrefix(String name, int offset) { } public void set(String name, String value) { - final Method method = setterMethods.get(name); + final Method method = requireNonNull( + setterMethods.get(name), + () -> "setter method " + name + " not found" + ); try { method.invoke(o, value); } catch (IllegalAccessException | InvocationTargetException e) { @@ -1422,8 +1427,11 @@ public void set(String name, String value) { } } - public Object get(String name) { - final Method method = getterMethods.get(name); + public @Nullable Object get(String name) { + final Method method = requireNonNull( + getterMethods.get(name), + () -> "getter method " + name + " not found" + ); try { return method.invoke(o); } catch (IllegalAccessException | InvocationTargetException e) { diff --git a/core/src/main/java/org/apache/calcite/sql/type/CursorReturnTypeInference.java b/core/src/main/java/org/apache/calcite/sql/type/CursorReturnTypeInference.java index 69f92148089e..c4cc272a8a58 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/CursorReturnTypeInference.java +++ b/core/src/main/java/org/apache/calcite/sql/type/CursorReturnTypeInference.java @@ -19,6 +19,8 @@ import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.sql.SqlOperatorBinding; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Returns the rowtype of a cursor of the operand at a particular 0-based * ordinal position. @@ -38,7 +40,7 @@ public CursorReturnTypeInference(int ordinal) { //~ Methods ---------------------------------------------------------------- - @Override public RelDataType inferReturnType( + @Override public @Nullable RelDataType inferReturnType( SqlOperatorBinding opBinding) { return opBinding.getCursorOperand(ordinal); } diff --git a/core/src/main/java/org/apache/calcite/sql/type/NonNullableAccessors.java b/core/src/main/java/org/apache/calcite/sql/type/NonNullableAccessors.java new file mode 100644 index 000000000000..eea2c685c71b --- /dev/null +++ b/core/src/main/java/org/apache/calcite/sql/type/NonNullableAccessors.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.calcite.sql.type; + +import org.apache.calcite.rel.type.RelDataType; +import org.apache.calcite.sql.SqlCollation; + +import org.apiguardian.api.API; + +import java.nio.charset.Charset; + +import static java.util.Objects.requireNonNull; + +/** + * This class provides non-nullable accessors for common getters. + */ +@API(since = "1.27", status = API.Status.EXPERIMENTAL) +public class NonNullableAccessors { + private NonNullableAccessors() { + } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + public static Charset getCharset(RelDataType type) { + return requireNonNull(type.getCharset(), + () -> "charset is null for " + type); + } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + public static SqlCollation getCollation(RelDataType type) { + return requireNonNull(type.getCollation(), + () -> !SqlTypeUtil.inCharFamily(type) + ? "collation is null for " + type + : "RelDataType object should have been assigned " + + "a (default) collation when calling deriveType, type=" + type); + } +} diff --git a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java index e0e1353147b0..c78704aa5ef8 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java +++ b/core/src/main/java/org/apache/calcite/sql/type/OperandTypes.java @@ -341,7 +341,7 @@ public static SqlOperandTypeChecker variadic( } final SqlLiteral arg = (SqlLiteral) node; - final BigDecimal value = (BigDecimal) arg.getValue(); + final BigDecimal value = arg.getValueAs(BigDecimal.class); if (value.compareTo(BigDecimal.ZERO) < 0 || hasFractionalPart(value)) { if (throwOnFailure) { diff --git a/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java b/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java index 44ede214a6c5..72889d5a8c16 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java +++ b/core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java @@ -34,8 +34,12 @@ import java.util.AbstractList; import java.util.List; +import static org.apache.calcite.sql.type.NonNullableAccessors.getCharset; +import static org.apache.calcite.sql.type.NonNullableAccessors.getCollation; import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * A collection of return-type inference strategies. */ @@ -642,10 +646,10 @@ public static ExplicitReturnTypeInference explicit(SqlTypeName typeName, argType1.getFullTypeString())); } - pickedCollation = + pickedCollation = requireNonNull( SqlCollation.getCoercibilityDyadicOperator( - argType0.getCollation(), argType1.getCollation()); - assert null != pickedCollation; + getCollation(argType0), getCollation(argType1)), + () -> "getCoercibilityDyadicOperator is null for " + argType0 + " and " + argType1); } // Determine whether result is variable-length @@ -672,16 +676,17 @@ public static ExplicitReturnTypeInference explicit(SqlTypeName typeName, ret = typeFactory.createSqlType(typeName, typePrecision); if (null != pickedCollation) { RelDataType pickedType; - if (argType0.getCollation().equals(pickedCollation)) { + if (getCollation(argType0).equals(pickedCollation)) { pickedType = argType0; - } else if (argType1.getCollation().equals(pickedCollation)) { + } else if (getCollation(argType1).equals(pickedCollation)) { pickedType = argType1; } else { - throw new AssertionError("should never come here"); + throw new AssertionError("should never come here, " + + "argType0=" + argType0 + ", argType1=" + argType1); } ret = typeFactory.createTypeWithCharsetAndCollation(ret, - pickedType.getCharset(), pickedType.getCollation()); + getCharset(pickedType), getCollation(pickedType)); } if (ret.getSqlTypeName() == SqlTypeName.NULL) { ret = typeFactory.createTypeWithNullability( diff --git a/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeChecker.java b/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeChecker.java index 4087102d9fe6..221028e06690 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeChecker.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeChecker.java @@ -27,6 +27,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Collections; import java.util.List; @@ -75,7 +77,7 @@ protected List getOperandList(int operandCount) { protected boolean checkOperandTypesImpl( SqlOperatorBinding operatorBinding, boolean throwOnFailure, - SqlCallBinding callBinding) { + @Nullable SqlCallBinding callBinding) { int nOperandsActual = nOperands; if (nOperandsActual == -1) { nOperandsActual = operatorBinding.getOperandCount(); diff --git a/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeExceptLastOperandChecker.java b/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeExceptLastOperandChecker.java index 7c34c1e4a36c..6c4403ce2721 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeExceptLastOperandChecker.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SameOperandTypeExceptLastOperandChecker.java @@ -24,11 +24,15 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Collections; import java.util.List; import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * Parameter type-checking strategy where all operand types except last one must be the same. */ @@ -50,7 +54,7 @@ public SameOperandTypeExceptLastOperandChecker( @Override protected boolean checkOperandTypesImpl( SqlOperatorBinding operatorBinding, boolean throwOnFailure, - SqlCallBinding callBinding) { + @Nullable SqlCallBinding callBinding) { int nOperandsActual = nOperands; if (nOperandsActual == -1) { nOperandsActual = operatorBinding.getOperandCount(); @@ -61,7 +65,7 @@ public SameOperandTypeExceptLastOperandChecker( getOperandList(operatorBinding.getOperandCount()); for (int i : operandList) { if (operatorBinding.isOperandNull(i, false)) { - if (callBinding.isTypeCoercionEnabled()) { + if (requireNonNull(callBinding, "callBinding").isTypeCoercionEnabled()) { types[i] = operatorBinding.getTypeFactory() .createSqlType(SqlTypeName.NULL); } else if (throwOnFailure) { diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java index de84d131b110..a6362f332171 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java @@ -515,7 +515,8 @@ private RelDataType copyMultisetType(RelDataType type, boolean nullable) { private RelDataType copyIntervalType(RelDataType type, boolean nullable) { return new IntervalSqlType(typeSystem, - type.getIntervalQualifier(), + requireNonNull(type.getIntervalQualifier(), + () -> "type.getIntervalQualifier() for " + type), nullable); } diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java index 2eac6a3bb631..8263fb5cf9ec 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java @@ -386,7 +386,7 @@ public int getDefaultScale() { /** * Gets the SqlTypeFamily containing this SqlTypeName. * - * @return containing family, or null for none + * @return containing family, or null for none (SYMBOL, DISTINCT, STRUCTURED, ROW, OTHER) */ public @Nullable SqlTypeFamily getFamily() { return family; diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeTransforms.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeTransforms.java index 384ce919271e..a1bb98484d21 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeTransforms.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeTransforms.java @@ -23,7 +23,11 @@ import org.apache.calcite.util.Util; import java.util.List; -import java.util.Objects; + +import static org.apache.calcite.sql.type.NonNullableAccessors.getCharset; +import static org.apache.calcite.sql.type.NonNullableAccessors.getCollation; + +import static java.util.Objects.requireNonNull; /** * SqlTypeTransforms defines a number of reusable instances of @@ -46,7 +50,7 @@ public abstract class SqlTypeTransforms { (opBinding, typeToTransform) -> SqlTypeUtil.makeNullableIfOperandsAre(opBinding.getTypeFactory(), opBinding.collectOperandTypes(), - Objects.requireNonNull(typeToTransform)); + requireNonNull(typeToTransform)); /** * Parameter type-inference transform strategy where a derived type is @@ -66,7 +70,7 @@ public abstract class SqlTypeTransforms { public static final SqlTypeTransform TO_NOT_NULLABLE = (opBinding, typeToTransform) -> opBinding.getTypeFactory().createTypeWithNullability( - Objects.requireNonNull(typeToTransform), false); + requireNonNull(typeToTransform), false); /** * Parameter type-inference transform strategy where a derived type is @@ -75,7 +79,7 @@ public abstract class SqlTypeTransforms { public static final SqlTypeTransform FORCE_NULLABLE = (opBinding, typeToTransform) -> opBinding.getTypeFactory().createTypeWithNullability( - Objects.requireNonNull(typeToTransform), true); + requireNonNull(typeToTransform), true); /** * Type-inference strategy whereby the result is NOT NULL if any of @@ -122,8 +126,8 @@ public abstract class SqlTypeTransforms { opBinding.getTypeFactory() .createTypeWithCharsetAndCollation( ret, - typeToTransform.getCharset(), - typeToTransform.getCollation()); + getCharset(typeToTransform), + getCollation(typeToTransform)); } return opBinding.getTypeFactory().createTypeWithNullability( ret, @@ -154,7 +158,9 @@ private SqlTypeName toVar(RelDataType type) { * @see MultisetSqlType#getComponentType */ public static final SqlTypeTransform TO_MULTISET_ELEMENT_TYPE = - (opBinding, typeToTransform) -> typeToTransform.getComponentType(); + (opBinding, typeToTransform) -> requireNonNull( + typeToTransform.getComponentType(), + () -> "componentType for " + typeToTransform + " in opBinding " + opBinding); /** * Parameter type-inference transform strategy that wraps a given type diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java index de4f60fa18bd..1c712bbfc712 100644 --- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java +++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeUtil.java @@ -60,6 +60,8 @@ import java.util.function.Function; import java.util.stream.Collectors; +import static org.apache.calcite.sql.type.NonNullableAccessors.getCharset; +import static org.apache.calcite.sql.type.NonNullableAccessors.getCollation; import static org.apache.calcite.util.Static.RESOURCE; import static java.util.Objects.requireNonNull; @@ -96,18 +98,12 @@ public static boolean isCharTypeComparable(List argTypes) { return false; } - if (t0.getCharset() == null) { - throw new AssertionError("RelDataType object should have been assigned " - + "a (default) charset when calling deriveType"); - } else if (!t0.getCharset().equals(t1.getCharset())) { + if (!getCharset(t0).equals(getCharset(t1))) { return false; } - if (t0.getCollation() == null) { - throw new AssertionError("RelDataType object should have been assigned " - + "a (default) collation when calling deriveType"); - } else if (!t0.getCollation().getCharset().equals( - t1.getCollation().getCharset())) { + if (!getCollation(t0).getCharset().equals( + getCollation(t1).getCharset())) { return false; } } @@ -345,12 +341,14 @@ public static boolean isTimestamp(RelDataType type) { } /** Returns whether a type is some kind of INTERVAL. */ + @EnsuresNonNullIf(expression = "#1.getIntervalQualifier()", result = true) public static boolean isInterval(RelDataType type) { return SqlTypeFamily.DATETIME_INTERVAL.contains(type); } /** Returns whether a type is in SqlTypeFamily.Character. */ @EnsuresNonNullIf(expression = "#1.getCharset()", result = true) + @EnsuresNonNullIf(expression = "#1.getCollation()", result = true) public static boolean inCharFamily(RelDataType type) { return type.getFamily() == SqlTypeFamily.CHARACTER; } @@ -586,7 +584,7 @@ public static int getMaxByteSize(RelDataType type) { case VARCHAR: return (int) Math.ceil( ((double) type.getPrecision()) - * type.getCharset().newEncoder().maxBytesPerChar()); + * getCharset(type).newEncoder().maxBytesPerChar()); case BINARY: case VARBINARY: diff --git a/core/src/main/java/org/apache/calcite/sql/util/SqlShuttle.java b/core/src/main/java/org/apache/calcite/sql/util/SqlShuttle.java index 499eab3469e4..7be504fc4998 100644 --- a/core/src/main/java/org/apache/calcite/sql/util/SqlShuttle.java +++ b/core/src/main/java/org/apache/calcite/sql/util/SqlShuttle.java @@ -64,7 +64,7 @@ public class SqlShuttle extends SqlBasicVisitor<@Nullable SqlNode> { @Override public @Nullable SqlNode visit(final SqlCall call) { // Handler creates a new copy of 'call' only if one or more operands // change. - ArgHandler argHandler = new CallCopyingArgHandler(call, false); + CallCopyingArgHandler argHandler = new CallCopyingArgHandler(call, false); call.getOperator().acceptCall(this, call, false, argHandler); return argHandler.result(); } @@ -73,7 +73,7 @@ public class SqlShuttle extends SqlBasicVisitor<@Nullable SqlNode> { boolean update = false; List exprs = nodeList.getList(); int exprCount = exprs.size(); - List newList = new ArrayList<>(exprCount); + List<@Nullable SqlNode> newList = new ArrayList<>(exprCount); for (SqlNode operand : exprs) { SqlNode clonedOperand; if (operand == null) { @@ -102,14 +102,14 @@ public class SqlShuttle extends SqlBasicVisitor<@Nullable SqlNode> { */ protected class CallCopyingArgHandler implements ArgHandler<@Nullable SqlNode> { boolean update; - SqlNode[] clonedOperands; + @Nullable SqlNode[] clonedOperands; private final SqlCall call; private final boolean alwaysCopy; public CallCopyingArgHandler(SqlCall call, boolean alwaysCopy) { this.call = call; this.update = false; - final List operands = call.getOperandList(); + final List<@Nullable SqlNode> operands = (List<@Nullable SqlNode>) call.getOperandList(); this.clonedOperands = operands.toArray(new SqlNode[0]); this.alwaysCopy = alwaysCopy; } 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 382184fd94e4..bac1db61c3cc 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 @@ -180,7 +180,7 @@ public String translate(String name) { return true; } - @Override public T unwrap(Class clazz) { + @Override public T unwrap(Class clazz) { return clazz.cast(this); } 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 27d535cb0c8e..97d6abdf1a32 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 @@ -103,7 +103,7 @@ protected DelegatingNamespace(SqlValidatorNamespace namespace) { @Override public void makeNullable() { } - @Override public T unwrap(Class clazz) { + @Override public T unwrap(Class clazz) { if (clazz.isInstance(this)) { return clazz.cast(this); } else { diff --git a/core/src/main/java/org/apache/calcite/sql/validate/DelegatingSqlValidatorCatalogReader.java b/core/src/main/java/org/apache/calcite/sql/validate/DelegatingSqlValidatorCatalogReader.java index 329b9ba45c5c..6f9b7531cbd2 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/DelegatingSqlValidatorCatalogReader.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/DelegatingSqlValidatorCatalogReader.java @@ -42,7 +42,7 @@ protected DelegatingSqlValidatorCatalogReader( this.catalogReader = catalogReader; } - @Override public SqlValidatorTable getTable(List names) { + @Override public @Nullable SqlValidatorTable getTable(List names) { return catalogReader.getTable(names); } @@ -58,7 +58,7 @@ protected DelegatingSqlValidatorCatalogReader( return catalogReader.getSchemaPaths(); } - @Override public @Nullable C unwrap(Class aClass) { + @Override public @Nullable C unwrap(Class aClass) { return catalogReader.unwrap(aClass); } } 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 f127fc764ec8..59607e746375 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 @@ -21,6 +21,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static java.util.Objects.requireNonNull; + /** * Implementation of {@link SqlValidatorNamespace} for a field of a record. * @@ -52,7 +54,7 @@ class FieldNamespace extends AbstractNamespace { } @Override protected RelDataType validateImpl(RelDataType targetRowType) { - return rowType; + return requireNonNull(rowType, "rowType"); } @Override public @Nullable SqlNode getNode() { @@ -60,7 +62,7 @@ class FieldNamespace extends AbstractNamespace { } @Override public @Nullable SqlValidatorNamespace lookupChild(String name) { - if (rowType.isStruct()) { + if (requireNonNull(rowType, "rowType").isStruct()) { return validator.lookupFieldNamespace( rowType, name); 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 c6a51164564e..43564fca16d8 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 @@ -42,9 +42,9 @@ class JoinNamespace extends AbstractNamespace { @Override protected RelDataType validateImpl(RelDataType targetRowType) { RelDataType leftType = - validator.getNamespace(join.getLeft()).getRowType(); + validator.getNamespaceOrThrow(join.getLeft()).getRowType(); RelDataType rightType = - validator.getNamespace(join.getRight()).getRowType(); + validator.getNamespaceOrThrow(join.getRight()).getRowType(); final RelDataTypeFactory typeFactory = validator.getTypeFactory(); switch (join.getJoinType()) { case LEFT: diff --git a/core/src/main/java/org/apache/calcite/sql/validate/ListScope.java b/core/src/main/java/org/apache/calcite/sql/validate/ListScope.java index 654d1d224f58..1c4061d49329 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/ListScope.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/ListScope.java @@ -102,18 +102,24 @@ public List getChildren() { if (table != null) { final ResolvedImpl resolved = new ResolvedImpl(); resolveTable(names, nameMatcher, Path.EMPTY, resolved); - if (resolved.count() == 1 - && resolved.only().remainingNames.isEmpty() - && resolved.only().namespace instanceof TableNamespace - && resolved.only().namespace.getTable().getQualifiedName().equals( - table.getQualifiedName())) { - return child; + if (resolved.count() == 1) { + Resolve only = resolved.only(); + List qualifiedName = table.getQualifiedName(); + if (only.remainingNames.isEmpty() + && only.namespace instanceof TableNamespace + && Objects.equals(qualifiedName, getQualifiedName(only.namespace.getTable()))) { + return child; + } } } } return null; } + private @Nullable List getQualifiedName(@Nullable SqlValidatorTable table) { + return table == null ? null : table.getQualifiedName(); + } + @Override public void findAllColumnNames(List result) { for (ScopeChild child : children) { addColumnNames(child.namespace, result); 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 06a74c86d343..91b4e70e3925 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 @@ -22,6 +22,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static java.util.Objects.requireNonNull; + /** * Namespace for a {@code MATCH_RECOGNIZE} clause. */ @@ -38,7 +40,7 @@ protected MatchRecognizeNamespace(SqlValidatorImpl validator, @Override public RelDataType validateImpl(RelDataType targetRowType) { validator.validateMatchRecognize(matchRecognize); - return rowType; + return requireNonNull(rowType, "rowType"); } @Override public @Nullable SqlNode getNode() { diff --git a/core/src/main/java/org/apache/calcite/sql/validate/PivotNamespace.java b/core/src/main/java/org/apache/calcite/sql/validate/PivotNamespace.java index 3b0dc256d73d..208dc80f959b 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/PivotNamespace.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/PivotNamespace.java @@ -20,6 +20,8 @@ import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.SqlPivot; +import static java.util.Objects.requireNonNull; + /** * Namespace for a {@code PIVOT} clause. */ @@ -35,7 +37,7 @@ protected PivotNamespace(SqlValidatorImpl validator, SqlPivot pivot, @Override public RelDataType validateImpl(RelDataType targetRowType) { validator.validatePivot(pivot); - return rowType; + return requireNonNull(rowType, "rowType"); } @Override public SqlPivot getNode() { diff --git a/core/src/main/java/org/apache/calcite/sql/validate/PivotScope.java b/core/src/main/java/org/apache/calcite/sql/validate/PivotScope.java index 4d208124c8ae..eb0436cbef4b 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/PivotScope.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/PivotScope.java @@ -18,6 +18,8 @@ import org.apache.calcite.sql.SqlPivot; +import static java.util.Objects.requireNonNull; + /** * Scope for expressions in a {@code PIVOT} clause. */ @@ -36,7 +38,9 @@ public PivotScope(SqlValidatorScope parent, SqlPivot pivot) { * {@link org.apache.calcite.sql.validate.ListScope#getChildren()}, but this * scope only has one namespace, and it is anonymous. */ public SqlValidatorNamespace getChild() { - return validator.getNamespace(pivot.query); + return requireNonNull( + validator.getNamespace(pivot.query), + () -> "namespace for pivot.query " + pivot.query); } @Override public SqlPivot getNode() { 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 8eeb26178526..9d97a252efa5 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 @@ -27,6 +27,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static java.util.Objects.requireNonNull; + /** * Namespace whose contents are defined by the result of a call to a * user-defined procedure. @@ -69,7 +71,9 @@ public class ProcedureNamespace extends AbstractNamespace { } final SqlReturnTypeInference rowTypeInference = tableFunction.getRowTypeInference(); - return rowTypeInference.inferReturnType(callBinding); + return requireNonNull( + rowTypeInference.inferReturnType(callBinding), + () -> "got null from inferReturnType for call " + callBinding.getCall()); } @Override public @Nullable SqlNode getNode() { 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 553ad377d424..f92b12d36036 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 @@ -20,6 +20,7 @@ import org.apache.calcite.sql.SqlCall; import org.apache.calcite.sql.SqlKind; import org.apache.calcite.sql.SqlNode; +import org.apache.calcite.util.Util; import org.checkerframework.checker.nullness.qual.Nullable; @@ -73,7 +74,7 @@ protected SetopNamespace( namespace.getMonotonicity( namespace.getRowType().getFieldNames().get(index))); } - return monotonicity; + return Util.first(monotonicity, SqlMonotonicity.NOT_MONOTONIC); } private SqlMonotonicity combine(@Nullable SqlMonotonicity m0, diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlNonNullableAccessors.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlNonNullableAccessors.java new file mode 100644 index 000000000000..d5cbc4c2a9a1 --- /dev/null +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlNonNullableAccessors.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.calcite.sql.validate; + +import org.apache.calcite.sql.SqlDelete; +import org.apache.calcite.sql.SqlJoin; +import org.apache.calcite.sql.SqlMerge; +import org.apache.calcite.sql.SqlNode; +import org.apache.calcite.sql.SqlNodeList; +import org.apache.calcite.sql.SqlSelect; +import org.apache.calcite.sql.SqlUpdate; + +import org.apiguardian.api.API; + +import java.util.Objects; + +import static java.util.Objects.requireNonNull; + +/** + * This class provides non-nullable accessors for common getters. + */ +@API(since = "1.27", status = API.Status.EXPERIMENTAL) +public class SqlNonNullableAccessors { + private SqlNonNullableAccessors() { + } + + private static String safeToString(Object obj) { + try { + return Objects.toString(obj); + } catch (Throwable e) { + return "Error in toString: " + e; + } + } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + public static SqlSelect getSourceSelect(SqlUpdate statement) { + return requireNonNull(statement.getSourceSelect(), + () -> "sourceSelect of " + safeToString(statement)); + } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + public static SqlSelect getSourceSelect(SqlDelete statement) { + return requireNonNull(statement.getSourceSelect(), + () -> "sourceSelect of " + safeToString(statement)); + } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + public static SqlSelect getSourceSelect(SqlMerge statement) { + return requireNonNull(statement.getSourceSelect(), + () -> "sourceSelect of " + safeToString(statement)); + } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + public static SqlNode getCondition(SqlJoin join) { + return requireNonNull(join.getCondition(), + () -> "getCondition of " + safeToString(join)); + } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + static SqlNode getNode(ScopeChild child) { + return requireNonNull(child.namespace.getNode(), + () -> "child.namespace.getNode() of " + child.name); + } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + public static SqlNodeList getSelectList(SqlSelect innerSelect) { + return requireNonNull(innerSelect.getSelectList(), + () -> "selectList of " + safeToString(innerSelect)); + } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + public static SqlValidatorTable getTable(SqlValidatorNamespace ns) { + return requireNonNull(ns.getTable(), + () -> "ns.getTable() for " + safeToString(ns)); + } +} diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlScopedShuttle.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlScopedShuttle.java index 1006374e1e88..ca4d55ff7a9a 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlScopedShuttle.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlScopedShuttle.java @@ -21,9 +21,13 @@ import org.apache.calcite.sql.util.SqlShuttle; import org.apache.calcite.sql.util.SqlVisitor; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayDeque; import java.util.Deque; +import static java.util.Objects.requireNonNull; + /** * Refinement to {@link SqlShuttle} which maintains a stack of scopes. * @@ -43,8 +47,8 @@ protected SqlScopedShuttle(SqlValidatorScope initialScope) { //~ Methods ---------------------------------------------------------------- - @Override public final SqlNode visit(SqlCall call) { - SqlValidatorScope oldScope = scopes.peek(); + @Override public final @Nullable SqlNode visit(SqlCall call) { + SqlValidatorScope oldScope = getScope(); SqlValidatorScope newScope = oldScope.getOperandScope(call); scopes.push(newScope); SqlNode result = visitScoped(call); @@ -56,7 +60,7 @@ protected SqlScopedShuttle(SqlValidatorScope initialScope) { * Visits an operator call. If the call has entered a new scope, the base * class will have already modified the scope. */ - protected SqlNode visitScoped(SqlCall call) { + protected @Nullable SqlNode visitScoped(SqlCall call) { return super.visit(call); } @@ -64,6 +68,6 @@ protected SqlNode visitScoped(SqlCall call) { * Returns the current scope. */ protected SqlValidatorScope getScope() { - return scopes.peek(); + return requireNonNull(scopes.peek(), "scopes.peek()"); } } 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 4e9f1c59a6b9..0f4bb4eb8795 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 @@ -171,7 +171,7 @@ SqlNode validateParameterizedExpression( * type 'unknown'. * @throws RuntimeException if the query is not valid */ - void validateQuery(SqlNode node, SqlValidatorScope scope, + void validateQuery(SqlNode node, @Nullable SqlValidatorScope scope, RelDataType targetRowType); /** @@ -545,7 +545,7 @@ void setValidatedNodeType( * @param select SELECT statement * @return naming scope for FROM clause */ - SqlValidatorScope getFromScope(SqlSelect select); + @Nullable SqlValidatorScope getFromScope(SqlSelect select); /** * Returns a scope containing the objects visible from the ON and USING @@ -556,7 +556,7 @@ void setValidatedNodeType( * @return naming scope for JOIN clause * @see #getFromScope */ - SqlValidatorScope getJoinScope(SqlNode node); + @Nullable SqlValidatorScope getJoinScope(SqlNode node); /** * Returns a scope containing the objects visible from the GROUP BY clause @@ -620,7 +620,7 @@ void setValidatedNodeType( * @param columnListParamName name of the column list parameter * @return name of the parent cursor */ - String getParentCursor(String columnListParamName); + @Nullable String getParentCursor(String columnListParamName); /** * Derives the type of a constructor. @@ -744,7 +744,7 @@ boolean validateModality(SqlSelect select, SqlModality modality, void validateSequenceValue(SqlValidatorScope scope, SqlIdentifier id); - SqlValidatorScope getWithScope(SqlNode withItem); + @Nullable SqlValidatorScope getWithScope(SqlNode withItem); /** Get the type coercion instance. */ TypeCoercion getTypeCoercion(); diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorCatalogReader.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorCatalogReader.java index 65b12a4d5367..9cfb3f89c6f4 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorCatalogReader.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorCatalogReader.java @@ -27,6 +27,7 @@ import java.util.List; + /** * Supplies catalog information for {@link SqlValidator}. * 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 0346f5cb255c..be851e3c401f 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 @@ -113,6 +113,8 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; +import org.apiguardian.api.API; +import org.checkerframework.checker.nullness.qual.KeyFor; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; import org.checkerframework.dataflow.qual.Pure; @@ -143,6 +145,10 @@ import static org.apache.calcite.linq4j.Nullness.castNonNull; import static org.apache.calcite.sql.SqlUtil.stripAs; +import static org.apache.calcite.sql.type.NonNullableAccessors.getCharset; +import static org.apache.calcite.sql.type.NonNullableAccessors.getCollation; +import static org.apache.calcite.sql.validate.SqlNonNullableAccessors.getCondition; +import static org.apache.calcite.sql.validate.SqlNonNullableAccessors.getTable; import static org.apache.calcite.util.Static.RESOURCE; import static java.util.Objects.requireNonNull; @@ -344,9 +350,7 @@ public SqlConformance getConformance() { types, includeSystemVars); } - requireNonNull( - getRawSelectScope(select), - () -> "rawSelectScope for " + select).setExpandedSelectList(list); + getRawSelectScopeNonNull(select).setExpandedSelectList(list); return new SqlNodeList(list, SqlParserPos.ZERO); } @@ -383,7 +387,7 @@ public SqlConformance getConformance() { } // implement SqlValidator - @Override public String getParentCursor(String columnListParamName) { + @Override public @Nullable String getParentCursor(String columnListParamName) { FunctionParamInfo funcParamInfo = requireNonNull(functionCallStack.peek(), "functionCall"); Map parentCursorMap = funcParamInfo.columnListParamToParentCursorMap; @@ -455,16 +459,16 @@ private boolean expandSelectItem( } private static SqlNode expandExprFromJoin(SqlJoin join, SqlIdentifier identifier, - SelectScope scope) { + @Nullable SelectScope scope) { if (join.getConditionType() != JoinConditionType.USING) { return identifier; } - for (SqlNode node : (SqlNodeList) join.getCondition()) { + for (SqlNode node : (SqlNodeList) getCondition(join)) { final String name = ((SqlIdentifier) node).getSimple(); if (identifier.getSimple().equals(name)) { final List qualifiedNode = new ArrayList<>(); - for (ScopeChild child : scope.children) { + for (ScopeChild child : requireNonNull(scope, "scope").children) { if (child.namespace.getRowType() .getFieldNames().indexOf(name) >= 0) { final SqlIdentifier exp = @@ -503,7 +507,7 @@ private static SqlNode expandExprFromJoin(SqlJoin join, SqlIdentifier identifier case USING: final ImmutableList.Builder list = ImmutableList.builder(); final Set names = catalogReader.nameMatcher().createSet(); - for (SqlNode node : (SqlNodeList) join.getCondition()) { + for (SqlNode node : (SqlNodeList) getCondition(join)) { final String name = ((SqlIdentifier) node).getSimple(); if (names.add(name)) { list.add(name); @@ -525,7 +529,7 @@ private static SqlNode expandExprFromJoin(SqlJoin join, SqlIdentifier identifier } private static SqlNode expandCommonColumn(SqlSelect sqlSelect, - SqlNode selectItem, SelectScope scope, SqlValidatorImpl validator) { + SqlNode selectItem, @Nullable SelectScope scope, SqlValidatorImpl validator) { if (!(selectItem instanceof SqlIdentifier)) { return selectItem; } @@ -547,13 +551,14 @@ private static SqlNode expandCommonColumn(SqlSelect sqlSelect, } private static void validateQualifiedCommonColumn(SqlJoin join, - SqlIdentifier identifier, SelectScope scope, SqlValidatorImpl validator) { + SqlIdentifier identifier, @Nullable SelectScope scope, SqlValidatorImpl validator) { List names = validator.usingNames(join); if (names == null) { // Not USING or NATURAL. return; } + requireNonNull(scope, "scope"); // First we should make sure that the first component is the table name. // Then check whether the qualified identifier contains common column. for (ScopeChild child : scope.children) { @@ -607,9 +612,8 @@ private boolean expandStar(List selectItems, Set aliases, scope, includeSystemVars); } else { - final SqlNode from = child.namespace.getNode(); - final SqlValidatorNamespace fromNs = getNamespace(from, scope); - assert fromNs != null; + final SqlNode from = SqlNonNullableAccessors.getNode(child); + final SqlValidatorNamespace fromNs = getNamespaceOrThrow(from, scope); final RelDataType rowType = fromNs.getRowType(); for (RelDataTypeField field : rowType.getFieldList()) { String columnName = field.getName(); @@ -647,7 +651,9 @@ private boolean expandStar(List selectItems, Set aliases, // If NATURAL JOIN or USING is present, move key fields to the front of // the list, per standard SQL. Disabled if there are dynamic fields. if (!hasDynamicStruct || Bug.CALCITE_2400_FIXED) { - new Permute(scope.getNode().getFrom(), 0).permute(selectItems, fields); + SqlNode from = requireNonNull(scope.getNode().getFrom(), + () -> "getFrom for " + scope.getNode()); + new Permute(from, 0).permute(selectItems, fields); } return true; @@ -811,14 +817,14 @@ private void lookupSelectHints( private void lookupFromHints( @Nullable SqlNode node, - SqlValidatorScope scope, + @Nullable SqlValidatorScope scope, SqlParserPos pos, Collection hintList) { if (node == null) { // This can happen in cases like "select * _suggest_", so from clause is absent return; } - final SqlValidatorNamespace ns = getNamespace(node); + final SqlValidatorNamespace ns = getNamespaceOrThrow(node); if (ns.isWrapperFor(IdentifierNamespace.class)) { IdentifierNamespace idNs = ns.unwrap(IdentifierNamespace.class); final SqlIdentifier id = idNs.getId(); @@ -851,7 +857,7 @@ private void lookupFromHints( private void lookupJoinHints( SqlJoin join, - SqlValidatorScope scope, + @Nullable SqlValidatorScope scope, SqlParserPos pos, Collection hintList) { SqlNode left = join.getLeft(); @@ -866,10 +872,12 @@ private void lookupJoinHints( return; } final JoinConditionType conditionType = join.getConditionType(); - final SqlValidatorScope joinScope = scopes.get(join); switch (conditionType) { case ON: - condition.findValidOptions(this, joinScope, pos, hintList); + requireNonNull(condition, () -> "join.getCondition() for " + join) + .findValidOptions(this, + getScopeOrThrow(join), + pos, hintList); return; default: @@ -1037,9 +1045,9 @@ private SqlNode validateScopedExpression( return outermostNode; } - @Override public void validateQuery(SqlNode node, SqlValidatorScope scope, + @Override public void validateQuery(SqlNode node, @Nullable SqlValidatorScope scope, RelDataType targetRowType) { - final SqlValidatorNamespace ns = getNamespace(node, scope); + final SqlValidatorNamespace ns = getNamespaceOrThrow(node, scope); if (node.getKind() == SqlKind.TABLESAMPLE) { List operands = ((SqlCall) node).getOperandList(); SqlSampleSpec sampleSpec = SqlLiteral.sampleValue(operands.get(1)); @@ -1056,7 +1064,7 @@ private SqlNode validateScopedExpression( switch (node.getKind()) { case EXTEND: // Until we have a dedicated namespace for EXTEND - deriveType(scope, node); + deriveType(requireNonNull(scope, "scope"), node); break; default: break; @@ -1119,6 +1127,11 @@ public SqlValidatorScope getCursorScope(SqlSelect select) { return (SelectScope) scope; } + private SelectScope getRawSelectScopeNonNull(SqlSelect select) { + return requireNonNull(getRawSelectScope(select), + () -> "getRawSelectScope for " + select); + } + @Override public SqlValidatorScope getHavingScope(SqlSelect select) { // Yes, it's the same as getSelectScope return getScope(select, Clause.SELECT); @@ -1129,7 +1142,7 @@ public SqlValidatorScope getCursorScope(SqlSelect select) { return getScope(select, Clause.WHERE); } - @Override public SqlValidatorScope getFromScope(SqlSelect select) { + @Override public @Nullable SqlValidatorScope getFromScope(SqlSelect select) { return scopes.get(select); } @@ -1138,15 +1151,19 @@ public SqlValidatorScope getCursorScope(SqlSelect select) { } @Override public SqlValidatorScope getMatchRecognizeScope(SqlMatchRecognize node) { - return scopes.get(node); + return getScopeOrThrow(node); } - @Override public SqlValidatorScope getJoinScope(SqlNode node) { + @Override public @Nullable SqlValidatorScope getJoinScope(SqlNode node) { return scopes.get(stripAs(node)); } @Override public SqlValidatorScope getOverScope(SqlNode node) { - return scopes.get(node); + return getScopeOrThrow(node); + } + + private SqlValidatorScope getScopeOrThrow(SqlNode node) { + return requireNonNull(scopes.get(node), () -> "scope for " + node); } private @Nullable SqlValidatorNamespace getNamespace(SqlNode node, @@ -1222,6 +1239,49 @@ public SqlValidatorScope getCursorScope(SqlSelect select) { } } + /** + * Namespace for the given node. + * @param node node to compute the namespace for + * @return namespace for the given node, never null + * @see #getNamespace(SqlNode) + */ + @API(since = "1.27", status = API.Status.INTERNAL) + SqlValidatorNamespace getNamespaceOrThrow(SqlNode node) { + return requireNonNull( + getNamespace(node), + () -> "namespace for " + node); + } + + /** + * Namespace for the given node. + * @param node node to compute the namespace for + * @param scope namespace scope + * @return namespace for the given node, never null + * @see #getNamespace(SqlNode) + */ + @API(since = "1.27", status = API.Status.INTERNAL) + SqlValidatorNamespace getNamespaceOrThrow(SqlNode node, + @Nullable SqlValidatorScope scope) { + return requireNonNull( + getNamespace(node, scope), + () -> "namespace for " + node + ", scope " + scope); + } + + /** + * Namespace for the given node. + * @param id identifier to resolve + * @param scope namespace scope + * @return namespace for the given node, never null + * @see #getNamespace(SqlIdentifier, DelegatingScope) + */ + @API(since = "1.26", status = API.Status.INTERNAL) + SqlValidatorNamespace getNamespaceOrThrow(SqlIdentifier id, + @Nullable DelegatingScope scope) { + return requireNonNull( + getNamespace(id, scope), + () -> "namespace for " + id + ", scope " + scope); + } + private void handleOffsetFetch(@Nullable SqlNode offset, @Nullable SqlNode fetch) { if (offset instanceof SqlDynamicParam) { setValidatedNodeType(offset, @@ -1370,9 +1430,7 @@ private void handleOffsetFetch(@Nullable SqlNode offset, @Nullable SqlNode fetch // We assume that ORDER BY item is present in SELECT list. for (int i = 0; i < orderList.size(); i++) { SqlNode sqlNode = orderList.get(i); - SqlNodeList selectList2 = requireNonNull( - innerSelect.getSelectList(), - () -> "selectList of " + innerSelect); + SqlNodeList selectList2 = SqlNonNullableAccessors.getSelectList(innerSelect); for (Ord sel : Ord.zip(selectList2)) { if (stripAs(sel.e).equalsDeep(sqlNode, Litmus.IGNORE)) { orderList.set(i, @@ -1458,13 +1516,8 @@ private void rewriteMerge(SqlMerge call) { // from the update statement's source since it's the same as // what we want for the select list of the merge source -- '*' // followed by the update set expressions - SqlSelect sourceSelect = requireNonNull( - updateStmt.getSourceSelect(), - () -> "sourceSelect of " + updateStmt); - selectList = SqlNode.clone( - requireNonNull( - sourceSelect.getSelectList(), - () -> "selectList of " + sourceSelect)); + SqlSelect sourceSelect = SqlNonNullableAccessors.getSourceSelect(updateStmt); + selectList = SqlNode.clone(SqlNonNullableAccessors.getSelectList(sourceSelect)); } else { // otherwise, just use select * selectList = new SqlNodeList(SqlParserPos.ZERO); @@ -1651,11 +1704,12 @@ protected SqlSelect createSourceSelectForDelete(SqlDelete call) { final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO); selectList.add(SqlIdentifier.star(SqlParserPos.ZERO)); SqlNode sourceTable = call.getTargetTable(); - if (call.getAlias() != null) { + SqlIdentifier alias = call.getAlias(); + if (alias != null) { sourceTable = SqlValidatorUtil.addAlias( sourceTable, - call.getAlias().getSimple()); + alias.getSimple()); } return new SqlSelect(SqlParserPos.ZERO, null, selectList, sourceTable, call.getCondition(), null, null, null, null, null, null, null); @@ -1916,8 +1970,8 @@ protected void inferUnknownTypes( newInferredType = typeFactory.createTypeWithCharsetAndCollation( newInferredType, - inferredType.getCharset(), - inferredType.getCollation()); + getCharset(inferredType), + getCollation(inferredType)); } setValidatedNodeType(node, newInferredType); } else if (node instanceof SqlNodeList) { @@ -2067,7 +2121,7 @@ private void registerPivot( SqlValidatorScope usingScope, SqlPivot call, SqlNode enclosingNode, - String alias, + @Nullable String alias, boolean forceNullable) { final PivotNamespace namespace = createPivotNameSpace(call, enclosingNode); @@ -2107,7 +2161,7 @@ protected void registerNamespace( @Nullable String alias, SqlValidatorNamespace ns, boolean forceNullable) { - namespaces.put(ns.getNode(), ns); + namespaces.put(requireNonNull(ns.getNode(), () -> "ns.getNode() for " + ns), ns); if (usingScope != null) { assert alias != null : "Registering namespace " + ns + ", into scope " + usingScope + ", so alias must not be null"; @@ -2352,7 +2406,7 @@ private SqlNode registerFrom( if (tableScope == null) { tableScope = new TableScope(parentScope, node); } - tableScope.addChild(newNs, alias, forceNullable); + tableScope.addChild(newNs, requireNonNull(alias, "alias"), forceNullable); if (extendList != null && extendList.size() != 0) { return enclosingNode; } @@ -2661,7 +2715,7 @@ private void registerQuery( aggScope, select, SqlSelect.HAVING_OPERAND); - registerSubQueries(aggScope, select.getSelectList()); + registerSubQueries(aggScope, SqlNonNullableAccessors.getSelectList(select)); final SqlNodeList orderList = select.getOrderList(); if (orderList != null) { // If the query is 'SELECT DISTINCT', restrict the columns @@ -2778,7 +2832,7 @@ private void registerQuery( registerQuery( parentScope, usingScope, - deleteCall.getSourceSelect(), + SqlNonNullableAccessors.getSourceSelect(deleteCall), enclosingNode, null, false); @@ -2800,7 +2854,7 @@ private void registerQuery( registerQuery( parentScope, usingScope, - updateCall.getSourceSelect(), + SqlNonNullableAccessors.getSourceSelect(updateCall), enclosingNode, null, false); @@ -2819,7 +2873,7 @@ private void registerQuery( registerQuery( parentScope, usingScope, - mergeCall.getSourceSelect(), + SqlNonNullableAccessors.getSourceSelect(mergeCall), enclosingNode, null, false); @@ -2828,21 +2882,23 @@ private void registerQuery( // or the target table, so set its parent scope to the merge's // source select; when validating the update, skip the feature // validation check - if (mergeCall.getUpdateCall() != null) { + SqlUpdate mergeUpdateCall = mergeCall.getUpdateCall(); + if (mergeUpdateCall != null) { registerQuery( - clauseScopes.get(IdPair.of(mergeCall.getSourceSelect(), Clause.WHERE)), + getScope(SqlNonNullableAccessors.getSourceSelect(mergeCall), Clause.WHERE), null, - mergeCall.getUpdateCall(), + mergeUpdateCall, enclosingNode, null, false, false); } - if (mergeCall.getInsertCall() != null) { + SqlInsert mergeInsertCall = mergeCall.getInsertCall(); + if (mergeInsertCall != null) { registerQuery( parentScope, null, - mergeCall.getInsertCall(), + mergeInsertCall, enclosingNode, null, false); @@ -2961,7 +3017,7 @@ private void registerWith( return true; } // Also when nested window aggregates are present - for (SqlCall call : overFinder.findAll(select.getSelectList())) { + for (SqlCall call : overFinder.findAll(SqlNonNullableAccessors.getSelectList(select))) { assert call.getKind() == SqlKind.OVER; if (isNestedAggregateWindow(call.operand(0))) { return true; @@ -3012,7 +3068,7 @@ protected boolean isOverAggregateWindow(SqlNode node) { return aggFinder.findAgg(selectList); } } - return aggFinder.findAgg(select.getSelectList()); + return aggFinder.findAgg(SqlNonNullableAccessors.getSelectList(select)); } @Deprecated @@ -3115,7 +3171,7 @@ private void registerOperandSubQueries( // // jhyde 2006/12/21: I think the limits should be baked into the // type system, not dependent on the calculator implementation. - BigDecimal bd = (BigDecimal) literal.getValue(); + BigDecimal bd = literal.getValueAs(BigDecimal.class); BigInteger unscaled = bd.unscaledValue(); long longValue = unscaled.longValue(); if (!BigInteger.valueOf(longValue).equals(unscaled)) { @@ -3130,7 +3186,7 @@ private void registerOperandSubQueries( break; case BINARY: - final BitString bitString = (BitString) literal.getValue(); + final BitString bitString = literal.getValueAs(BitString.class); if ((bitString.getBitCount() % 8) != 0) { throw newValidationError(literal, RESOURCE.binaryLiteralOdd()); } @@ -3182,7 +3238,7 @@ private void registerOperandSubQueries( } private void validateLiteralAsDouble(SqlLiteral literal) { - BigDecimal bd = (BigDecimal) literal.getValue(); + BigDecimal bd = literal.getValueAs(BigDecimal.class); double d = bd.doubleValue(); if (Double.isInfinite(d) || Double.isNaN(d)) { // overflow @@ -3268,7 +3324,7 @@ protected void validateFrom( // Validate the namespace representation of the node, just in case the // validation did not occur implicitly. - getNamespace(node, scope).validate(targetRowType); + getNamespaceOrThrow(node, scope).validate(targetRowType); } protected void validateOver(SqlCall call, SqlValidatorScope scope) { @@ -3289,7 +3345,7 @@ private void checkRollUpInUsing(SqlIdentifier identifier, if (namespace != null) { SqlValidatorTable sqlValidatorTable = namespace.getTable(); if (sqlValidatorTable != null) { - Table table = sqlValidatorTable.unwrap(Table.class); + Table table = sqlValidatorTable.unwrapOrThrow(Table.class); String column = Util.last(identifier.names); if (table.isRolledUp(column)) { @@ -3307,7 +3363,7 @@ protected void validateJoin(SqlJoin join, SqlValidatorScope scope) { boolean natural = join.isNatural(); final JoinType joinType = join.getJoinType(); final JoinConditionType conditionType = join.getConditionType(); - final SqlValidatorScope joinScope = scopes.get(join); + final SqlValidatorScope joinScope = getScopeOrThrow(join); // getJoinScope? validateFrom(left, unknownType, joinScope); validateFrom(right, unknownType, joinScope); @@ -3317,15 +3373,15 @@ protected void validateJoin(SqlJoin join, SqlValidatorScope scope) { Preconditions.checkArgument(condition == null); break; case ON: - Preconditions.checkArgument(condition != null); + requireNonNull(condition, "join.getCondition()"); SqlNode expandedCondition = expand(condition, joinScope); join.setOperand(5, expandedCondition); - condition = join.getCondition(); + condition = getCondition(join); validateWhereOrOn(joinScope, condition, "ON"); checkRollUp(null, join, condition, joinScope, "ON"); break; case USING: - SqlNodeList list = (SqlNodeList) condition; + SqlNodeList list = (SqlNodeList) requireNonNull(condition, "join.getCondition()"); // Parser ensures that using clause is not empty. Preconditions.checkArgument(list.size() > 0, "Empty USING clause"); @@ -3355,8 +3411,8 @@ protected void validateJoin(SqlJoin join, SqlValidatorScope scope) { // Join on fields that occur exactly once on each side. Ignore // fields that occur more than once on either side. - final RelDataType leftRowType = getNamespace(left).getRowType(); - final RelDataType rightRowType = getNamespace(right).getRowType(); + final RelDataType leftRowType = getNamespaceOrThrow(left).getRowType(); + final RelDataType rightRowType = getNamespaceOrThrow(right).getRowType(); final SqlNameMatcher nameMatcher = catalogReader.nameMatcher(); List naturalColumnNames = SqlValidatorUtil.deriveNaturalJoinColumnList(nameMatcher, @@ -3364,10 +3420,12 @@ protected void validateJoin(SqlJoin join, SqlValidatorScope scope) { // Check compatibility of the chosen columns. for (String name : naturalColumnNames) { - final RelDataType leftColType = - nameMatcher.field(leftRowType, name).getType(); - final RelDataType rightColType = - nameMatcher.field(rightRowType, name).getType(); + final RelDataType leftColType = requireNonNull( + nameMatcher.field(leftRowType, name), + () -> "unable to find left field " + name + " in " + leftRowType).getType(); + final RelDataType rightColType = requireNonNull( + nameMatcher.field(rightRowType, name), + () -> "unable to find right field " + name + " in " + rightRowType).getType(); if (!SqlTypeUtil.isComparable(leftColType, rightColType)) { throw newValidationError(join, RESOURCE.naturalOrUsingColumnNotCompatible(name, @@ -3439,7 +3497,7 @@ private void validateNoAggs(AggFinder aggFinder, SqlNode node, private RelDataType validateUsingCol(SqlIdentifier id, SqlNode leftOrRight) { if (id.names.size() == 1) { String name = id.names.get(0); - final SqlValidatorNamespace namespace = getNamespace(leftOrRight); + final SqlValidatorNamespace namespace = getNamespaceOrThrow(leftOrRight); final RelDataType rowType = namespace.getRowType(); final SqlNameMatcher nameMatcher = catalogReader.nameMatcher(); final RelDataTypeField field = nameMatcher.field(rowType, name); @@ -3467,22 +3525,21 @@ protected void validateSelect( assert targetRowType != null; // Namespace is either a select namespace or a wrapper around one. final SelectNamespace ns = - getNamespace(select).unwrap(SelectNamespace.class); + getNamespaceOrThrow(select).unwrap(SelectNamespace.class); // Its rowtype is null, meaning it hasn't been validated yet. // This is important, because we need to take the targetRowType into // account. assert ns.rowType == null; - if (select.isDistinct()) { + SqlNode distinctNode = select.getModifierNode(SqlSelectKeyword.DISTINCT); + if (distinctNode != null) { validateFeature(RESOURCE.sQLFeature_E051_01(), - select.getModifierNode(SqlSelectKeyword.DISTINCT) + distinctNode .getParserPosition()); } - final SqlNodeList selectItems = requireNonNull( - select.getSelectList(), - () -> "selectList of " + select); + final SqlNodeList selectItems = SqlNonNullableAccessors.getSelectList(select); RelDataType fromType = unknownType; if (selectItems.size() == 1) { final SqlNode selectItem = selectItems.get(0); @@ -3500,11 +3557,13 @@ protected void validateSelect( } // Make sure that items in FROM clause have distinct aliases. - final SelectScope fromScope = (SelectScope) getFromScope(select); + final SelectScope fromScope = (SelectScope) requireNonNull(getFromScope(select), + () -> "fromScope for " + select); List<@Nullable String> names = fromScope.getChildNames(); if (!catalogReader.nameMatcher().isCaseSensitive()) { + //noinspection RedundantTypeArguments names = names.stream() - .map(s -> s == null ? null : s.toUpperCase(Locale.ROOT)) + .<@Nullable String>map(s -> s == null ? null : s.toUpperCase(Locale.ROOT)) .collect(Collectors.toList()); } final int duplicateAliasOrdinal = Util.firstDuplicate(names); @@ -3556,7 +3615,7 @@ protected void validateSelect( private void checkRollUpInSelectList(SqlSelect select) { SqlValidatorScope scope = getSelectScope(select); - for (SqlNode item : select.getSelectList()) { + for (SqlNode item : SqlNonNullableAccessors.getSelectList(select)) { checkRollUp(null, select, item, scope); } } @@ -3612,14 +3671,16 @@ private void checkRollUp(@Nullable SqlNode grandParent, @Nullable SqlNode parent checkRollUpInWindow(getWindowInOver(current), scope); current = stripOver(current); - List<@Nullable SqlNode> children = ((SqlCall) stripAs(stripDot(current))).getOperandList(); + SqlNode stripDot = requireNonNull(stripDot(current), "stripDot(current)"); + List children = + ((SqlCall) stripAs(stripDot)).getOperandList(); for (SqlNode child : children) { checkRollUp(parent, current, child, scope, optionalClause); } } else if (current instanceof SqlIdentifier) { SqlIdentifier id = (SqlIdentifier) current; if (!id.isStar() && isRolledUpColumn(id, scope)) { - if (!isAggregation(parent.getKind()) + if (!isAggregation(requireNonNull(parent, "parent").getKind()) || !isRolledUpColumnAllowedInAgg(id, scope, (SqlCall) parent, grandParent)) { String context = optionalClause != null ? optionalClause : parent.getKind().toString(); throw newValidationError(id, @@ -3696,9 +3757,7 @@ private boolean isRolledUpColumnAllowedInAgg(SqlIdentifier identifier, SqlValida SqlValidatorTable sqlValidatorTable = fullyQualified.namespace.getTable(); if (sqlValidatorTable != null) { - Table table = sqlValidatorTable.unwrap(Table.class); - assert table != null : "unwrap(Table) returned null for " + sqlValidatorTable; - return table; + return sqlValidatorTable.unwrapOrThrow(Table.class); } return null; } @@ -3774,7 +3833,7 @@ private SqlModality deduceModality(SqlNode query) { @Override public boolean validateModality(SqlSelect select, SqlModality modality, boolean fail) { - final SelectScope scope = getRawSelectScope(select); + final SelectScope scope = getRawSelectScopeNonNull(select); switch (modality) { case STREAM: @@ -3782,7 +3841,8 @@ private SqlModality deduceModality(SqlNode query) { for (ScopeChild child : scope.children) { if (!child.namespace.supportsModality(modality)) { if (fail) { - throw newValidationError(child.namespace.getNode(), + SqlNode node = SqlNonNullableAccessors.getNode(child); + throw newValidationError(node, Static.RESOURCE.cannotConvertToStream(child.name)); } else { return false; @@ -3812,7 +3872,8 @@ private SqlModality deduceModality(SqlNode query) { for (ScopeChild child : scope.children) { if (!child.namespace.supportsModality(modality)) { if (fail) { - throw newValidationError(child.namespace.getNode(), + SqlNode node = SqlNonNullableAccessors.getNode(child); + throw newValidationError(node, Static.RESOURCE.cannotConvertToRelation(child.name)); } else { return false; @@ -3898,13 +3959,14 @@ protected void validateWindowClause(SqlSelect select) { return; } - final SelectScope windowScope = (SelectScope) getFromScope(select); - assert windowScope != null : "getFromScope returned null for " + select; + final SelectScope windowScope = (SelectScope) requireNonNull(getFromScope(select), + () -> "fromScope for " + select); // 1. ensure window names are simple // 2. ensure they are unique within this scope for (SqlWindow window : windows) { - SqlIdentifier declName = window.getDeclName(); + SqlIdentifier declName = requireNonNull(window.getDeclName(), + () -> "window.getDeclName() for " + window); if (!declName.isSimple()) { throw newValidationError(declName, RESOURCE.windowNameMustBeSimple()); } @@ -3945,20 +4007,21 @@ protected void validateWindowClause(SqlSelect select) { } @Override public void validateWith(SqlWith with, SqlValidatorScope scope) { - final SqlValidatorNamespace namespace = getNamespace(with); + final SqlValidatorNamespace namespace = getNamespaceOrThrow(with); validateNamespace(namespace, unknownType); } @Override public void validateWithItem(SqlWithItem withItem) { - if (withItem.columnList != null) { + SqlNodeList columnList = withItem.columnList; + if (columnList != null) { final RelDataType rowType = getValidatedNodeType(withItem.query); final int fieldCount = rowType.getFieldCount(); - if (withItem.columnList.size() != fieldCount) { - throw newValidationError(withItem.columnList, + if (columnList.size() != fieldCount) { + throw newValidationError(columnList, RESOURCE.columnCountMismatch()); } SqlValidatorUtil.checkIdentifierListForDuplicates( - withItem.columnList.getList(), validationErrorFunction); + columnList.getList(), validationErrorFunction); } else { // Luckily, field names have not been make unique yet. final List fieldNames = @@ -3983,7 +4046,7 @@ protected void validateWindowClause(SqlSelect select) { // We've found a table. But is it a sequence? final SqlValidatorNamespace ns = resolved.only().namespace; if (ns instanceof TableNamespace) { - final Table table = ns.getTable().unwrap(Table.class); + final Table table = getTable(ns).unwrapOrThrow(Table.class); switch (table.getJdbcTableType()) { case SEQUENCE: case TEMPORARY_SEQUENCE: @@ -3995,7 +4058,7 @@ protected void validateWindowClause(SqlSelect select) { throw newValidationError(id, RESOURCE.notASequence(id.toString())); } - @Override public SqlValidatorScope getWithScope(SqlNode withItem) { + @Override public @Nullable SqlValidatorScope getWithScope(SqlNode withItem) { assert withItem.getKind() == SqlKind.WITH_ITEM; return scopes.get(withItem); } @@ -4311,7 +4374,7 @@ protected RelDataType validateSelectList( if (config.identifierExpansion()) { select.setSelectList(newSelectList); } - getRawSelectScope(select).setExpandedSelectList(expandedSelectItems); + getRawSelectScopeNonNull(select).setExpandedSelectList(expandedSelectItems); // TODO: when SELECT appears as a value sub-query, should be using // something other than unknownType for targetRowType @@ -4369,7 +4432,7 @@ private void handleScalarSubQuery( Set aliasList, List> fieldList) { // A scalar sub-query only has one output column. - if (1 != selectItem.getSelectList().size()) { + if (1 != SqlNonNullableAccessors.getSelectList(selectItem).size()) { throw newValidationError(selectItem, RESOURCE.onlyScalarSubQueryAllowed()); } @@ -4447,13 +4510,13 @@ protected RelDataType createTargetRowType( } @Override public void validateInsert(SqlInsert insert) { - final SqlValidatorNamespace targetNamespace = getNamespace(insert); + final SqlValidatorNamespace targetNamespace = getNamespaceOrThrow(insert); validateNamespace(targetNamespace, unknownType); final RelOptTable relOptTable = SqlValidatorUtil.getRelOptTable( targetNamespace, catalogReader.unwrap(Prepare.CatalogReader.class), null, null); final SqlValidatorTable table = relOptTable == null - ? targetNamespace.getTable() - : relOptTable.unwrap(SqlValidatorTable.class); + ? getTable(targetNamespace) + : relOptTable.unwrapOrThrow(SqlValidatorTable.class); // INSERT has an optional column name list. If present then // reduce the rowtype to the columns specified. If not present @@ -4478,7 +4541,7 @@ protected RelDataType createTargetRowType( // from validateSelect above). It would be better if that information // were used here so that we never saw any untyped nulls during // checkTypeAssignment. - final RelDataType sourceRowType = getNamespace(source).getRowType(); + final RelDataType sourceRowType = getNamespaceOrThrow(source).getRowType(); final RelDataType logicalTargetRowType = getLogicalTargetRowType(targetRowType, insert); setValidatedNodeType(insert, logicalTargetRowType); @@ -4486,7 +4549,7 @@ protected RelDataType createTargetRowType( getLogicalSourceRowType(sourceRowType, insert); final List strategies = - table.unwrap(RelOptTable.class).getColumnStrategies(); + table.unwrapOrThrow(RelOptTable.class).getColumnStrategies(); final RelDataType realTargetRowType = typeFactory.createStructType( logicalTargetRowType.getFieldList() @@ -4530,7 +4593,7 @@ private void checkConstraint( final ModifiableViewTable modifiableViewTable = validatorTable.unwrap(ModifiableViewTable.class); if (modifiableViewTable != null && source instanceof SqlCall) { - final Table table = modifiableViewTable.unwrap(Table.class); + final Table table = modifiableViewTable.unwrapOrThrow(Table.class); final RelDataType tableRowType = table.getRowType(typeFactory); final List tableFields = tableRowType.getFieldList(); @@ -4543,16 +4606,19 @@ private void checkConstraint( // Determine columns (indexed to the underlying table) that need // to be validated against the view constraint. + @SuppressWarnings("RedundantCast") final ImmutableBitSet targetColumns = - ImmutableBitSet.of(tableIndexToTargetField.keySet()); + ImmutableBitSet.of((Iterable) tableIndexToTargetField.keySet()); + @SuppressWarnings("RedundantCast") final ImmutableBitSet constrainedColumns = - ImmutableBitSet.of(projectMap.keySet()); - final ImmutableBitSet constrainedTargetColumns = - targetColumns.intersect(constrainedColumns); + ImmutableBitSet.of((Iterable) projectMap.keySet()); + @SuppressWarnings("assignment.type.incompatible") + List<@KeyFor({"tableIndexToTargetField", "projectMap"}) Integer> constrainedTargetColumns = + targetColumns.intersect(constrainedColumns).asList(); // Validate insert values against the view constraint. final List values = ((SqlCall) source).getOperandList(); - for (final int colIndex : constrainedTargetColumns.asList()) { + for (final int colIndex: constrainedTargetColumns) { final String colName = tableFields.get(colIndex).getName(); final RelDataTypeField targetField = tableIndexToTargetField.get(colIndex); for (SqlNode row : values) { @@ -4584,7 +4650,7 @@ private void checkConstraint( final ModifiableViewTable modifiableViewTable = validatorTable.unwrap(ModifiableViewTable.class); if (modifiableViewTable != null) { - final Table table = modifiableViewTable.unwrap(Table.class); + final Table table = modifiableViewTable.unwrapOrThrow(Table.class); final RelDataType tableRowType = table.getRowType(typeFactory); final Map projectMap = @@ -4707,14 +4773,14 @@ protected RelDataType getLogicalTargetRowType( && this.config.sqlConformance().isInsertSubsetColumnsAllowed()) { // Target an implicit subset of columns. final SqlNode source = insert.getSource(); - final RelDataType sourceRowType = getNamespace(source).getRowType(); + final RelDataType sourceRowType = getNamespaceOrThrow(source).getRowType(); final RelDataType logicalSourceRowType = getLogicalSourceRowType(sourceRowType, insert); final RelDataType implicitTargetRowType = typeFactory.createStructType( targetRowType.getFieldList() .subList(0, logicalSourceRowType.getFieldCount())); - final SqlValidatorNamespace targetNamespace = getNamespace(insert); + final SqlValidatorNamespace targetNamespace = getNamespaceOrThrow(insert); validateNamespace(targetNamespace, implicitTargetRowType); return implicitTargetRowType; } else { @@ -4745,7 +4811,7 @@ protected RelDataType getLogicalSourceRowType( * @param query The query */ protected void checkTypeAssignment( - SqlValidatorScope sourceScope, + @Nullable SqlValidatorScope sourceScope, SqlValidatorTable table, RelDataType sourceRowType, RelDataType targetRowType, @@ -4839,14 +4905,15 @@ private SqlNode getNthExpr(SqlNode query, int ordinal, int sourceCount) { return update.getSourceExpressionList().get(ordinal); } else { return getNthExpr( - update.getSourceSelect(), + SqlNonNullableAccessors.getSourceSelect(update), ordinal, sourceCount); } } else if (query instanceof SqlSelect) { SqlSelect select = (SqlSelect) query; - if (select.getSelectList().size() == sourceCount) { - return select.getSelectList().get(ordinal); + SqlNodeList selectList = SqlNonNullableAccessors.getSelectList(select); + if (selectList.size() == sourceCount) { + return selectList.get(ordinal); } else { return query; // give up } @@ -4856,10 +4923,10 @@ private SqlNode getNthExpr(SqlNode query, int ordinal, int sourceCount) { } @Override public void validateDelete(SqlDelete call) { - final SqlSelect sqlSelect = call.getSourceSelect(); + final SqlSelect sqlSelect = SqlNonNullableAccessors.getSourceSelect(call); validateSelect(sqlSelect, unknownType); - final SqlValidatorNamespace targetNamespace = getNamespace(call); + final SqlValidatorNamespace targetNamespace = getNamespaceOrThrow(call); validateNamespace(targetNamespace, unknownType); final SqlValidatorTable table = targetNamespace.getTable(); @@ -4867,15 +4934,14 @@ private SqlNode getNthExpr(SqlNode query, int ordinal, int sourceCount) { } @Override public void validateUpdate(SqlUpdate call) { - final SqlValidatorNamespace targetNamespace = getNamespace(call); - assert targetNamespace != null : "targetNamespace was not found for call " + call; + final SqlValidatorNamespace targetNamespace = getNamespaceOrThrow(call); validateNamespace(targetNamespace, unknownType); final RelOptTable relOptTable = SqlValidatorUtil.getRelOptTable( targetNamespace, castNonNull(catalogReader.unwrap(Prepare.CatalogReader.class)), null, null); final SqlValidatorTable table = relOptTable == null - ? targetNamespace.getTable() - : relOptTable.unwrap(SqlValidatorTable.class); + ? getTable(targetNamespace) + : relOptTable.unwrapOrThrow(SqlValidatorTable.class); final RelDataType targetRowType = createTargetRowType( @@ -4883,7 +4949,7 @@ targetNamespace, castNonNull(catalogReader.unwrap(Prepare.CatalogReader.class)), call.getTargetColumnList(), true); - final SqlSelect select = call.getSourceSelect(); + final SqlSelect select = SqlNonNullableAccessors.getSourceSelect(call); validateSelect(select, targetRowType); final RelDataType sourceRowType = getValidatedNodeType(select); @@ -4899,7 +4965,7 @@ targetNamespace, castNonNull(catalogReader.unwrap(Prepare.CatalogReader.class)), } @Override public void validateMerge(SqlMerge call) { - SqlSelect sqlSelect = call.getSourceSelect(); + SqlSelect sqlSelect = SqlNonNullableAccessors.getSourceSelect(call); // REVIEW zfong 5/25/06 - Does an actual type have to be passed into // validateSelect()? @@ -4913,7 +4979,7 @@ targetNamespace, castNonNull(catalogReader.unwrap(Prepare.CatalogReader.class)), // since validateSelect() would bail. // Let's use the update/insert targetRowType when available. IdentifierNamespace targetNamespace = - (IdentifierNamespace) getNamespace(call.getTargetTable()); + (IdentifierNamespace) getNamespaceOrThrow(call.getTargetTable()); validateNamespace(targetNamespace, unknownType); SqlValidatorTable table = targetNamespace.getTable(); @@ -4921,26 +4987,32 @@ targetNamespace, castNonNull(catalogReader.unwrap(Prepare.CatalogReader.class)), RelDataType targetRowType = unknownType; - if (call.getUpdateCall() != null) { + SqlUpdate updateCall = call.getUpdateCall(); + if (updateCall != null) { + requireNonNull(table, () -> "ns.getTable() for " + targetNamespace); targetRowType = createTargetRowType( table, - call.getUpdateCall().getTargetColumnList(), + updateCall.getTargetColumnList(), true); } - if (call.getInsertCall() != null) { + SqlInsert insertCall = call.getInsertCall(); + if (insertCall != null) { + requireNonNull(table, () -> "ns.getTable() for " + targetNamespace); targetRowType = createTargetRowType( table, - call.getInsertCall().getTargetColumnList(), + insertCall.getTargetColumnList(), false); } validateSelect(sqlSelect, targetRowType); - if (call.getUpdateCall() != null) { - validateUpdate(call.getUpdateCall()); + SqlUpdate updateCallAfterValidate = call.getUpdateCall(); + if (updateCallAfterValidate != null) { + validateUpdate(updateCallAfterValidate); } - if (call.getInsertCall() != null) { - validateInsert(call.getInsertCall()); + SqlInsert insertCallAfterValidate = call.getInsertCall(); + if (insertCallAfterValidate != null) { + validateInsert(insertCallAfterValidate); } } @@ -4952,7 +5024,7 @@ targetNamespace, castNonNull(catalogReader.unwrap(Prepare.CatalogReader.class)), */ private void validateAccess( SqlNode node, - SqlValidatorTable table, + @Nullable SqlValidatorTable table, SqlAccessEnum requiredAccess) { if (table != null) { SqlAccessType access = table.getAllowedAccess(); @@ -4973,18 +5045,19 @@ private void validateAccess( */ private void validateSnapshot( SqlNode node, - SqlValidatorScope scope, + @Nullable SqlValidatorScope scope, SqlValidatorNamespace ns) { if (node.getKind() == SqlKind.SNAPSHOT) { SqlSnapshot snapshot = (SqlSnapshot) node; SqlNode period = snapshot.getPeriod(); - RelDataType dataType = deriveType(scope, period); + RelDataType dataType = deriveType(requireNonNull(scope, "scope"), period); if (dataType.getSqlTypeName() != SqlTypeName.TIMESTAMP) { throw newValidationError(period, Static.RESOURCE.illegalExpressionForTemporal(dataType.getSqlTypeName().getName())); } - if (!ns.getTable().isTemporal()) { - List qualifiedName = ns.getTable().getQualifiedName(); + SqlValidatorTable table = getTable(ns); + if (!table.isTemporal()) { + List qualifiedName = table.getQualifiedName(); String tableName = qualifiedName.get(qualifiedName.size() - 1); throw newValidationError(snapshot.getTableRef(), Static.RESOURCE.notTemporalTable(tableName)); @@ -5240,7 +5313,7 @@ public void setOriginal(SqlNode expr, SqlNode original) { (MatchRecognizeScope) getMatchRecognizeScope(matchRecognize); final MatchRecognizeNamespace ns = - getNamespace(call).unwrap(MatchRecognizeNamespace.class); + getNamespaceOrThrow(call).unwrap(MatchRecognizeNamespace.class); assert ns.rowType == null; // rows per match @@ -5270,9 +5343,10 @@ public void setOriginal(SqlNode expr, SqlNode original) { node.validate(this, scope); SqlIdentifier identifier; if (node instanceof SqlBasicCall) { - identifier = (SqlIdentifier) ((SqlBasicCall) node).getOperands()[0]; + identifier = (SqlIdentifier) ((SqlBasicCall) node).operand(0); } else { - identifier = (SqlIdentifier) node; + identifier = (SqlIdentifier) requireNonNull(node, + () -> "order by field is null. All fields: " + orderBy); } if (allRows) { @@ -5287,7 +5361,7 @@ public void setOriginal(SqlNode expr, SqlNode original) { if (allRows) { final SqlValidatorNamespace sqlNs = - getNamespace(matchRecognize.getTableRef()); + getNamespaceOrThrow(matchRecognize.getTableRef()); final RelDataType inputDataType = sqlNs.getRowType(); for (RelDataTypeField fs : inputDataType.getFieldList()) { if (!typeBuilder.nameExists(fs.getName())) { @@ -5305,8 +5379,10 @@ public void setOriginal(SqlNode expr, SqlNode original) { if (interval != null) { interval.validate(this, scope); if (((SqlIntervalLiteral) interval).signum() < 0) { + String intervalValue = interval.toValue(); throw newValidationError(interval, - RESOURCE.intervalMustBeNonNegative(interval.toValue())); + RESOURCE.intervalMustBeNonNegative( + intervalValue != null ? intervalValue : interval.toString())); } if (orderBy == null || orderBy.size() == 0) { throw newValidationError(interval, @@ -5316,9 +5392,9 @@ public void setOriginal(SqlNode expr, SqlNode original) { SqlNode firstOrderByColumn = orderBy.getList().get(0); SqlIdentifier identifier; if (firstOrderByColumn instanceof SqlBasicCall) { - identifier = (SqlIdentifier) ((SqlBasicCall) firstOrderByColumn).getOperands()[0]; + identifier = ((SqlBasicCall) firstOrderByColumn).operand(0); } else { - identifier = (SqlIdentifier) firstOrderByColumn; + identifier = (SqlIdentifier) requireNonNull(firstOrderByColumn, "firstOrderByColumn"); } RelDataType firstOrderByColumnType = deriveType(scope, identifier); if (firstOrderByColumnType.getSqlTypeName() != SqlTypeName.TIMESTAMP) { @@ -5375,7 +5451,7 @@ public void setOriginal(SqlNode expr, SqlNode original) { final RelDataType rowType = typeBuilder.build(); if (matchRecognize.getMeasureList().size() == 0) { - ns.setType(getNamespace(matchRecognize.getTableRef()).getRowType()); + ns.setType(getNamespaceOrThrow(matchRecognize.getTableRef()).getRowType()); } else { ns.setType(rowType); } @@ -5482,10 +5558,11 @@ private void validateDefinitions(SqlMatchRecognize mr, } public void validatePivot(SqlPivot pivot) { - final PivotScope scope = (PivotScope) getJoinScope(pivot); + final PivotScope scope = (PivotScope) requireNonNull(getJoinScope(pivot), + () -> "joinScope for " + pivot); final PivotNamespace ns = - getNamespace(pivot).unwrap(PivotNamespace.class); + getNamespaceOrThrow(pivot).unwrap(PivotNamespace.class); assert ns.rowType == null; // Given @@ -5499,7 +5576,7 @@ public void validatePivot(SqlPivot pivot) { // an aggregate or as an axis. // Aggregates, e.g. "PIVOT (sum(x) AS sum_x, count(*) AS c)" - final List> aggNames = new ArrayList<>(); + final List> aggNames = new ArrayList<>(); pivot.forEachAgg((alias, call) -> { call.validate(this, scope); final RelDataType type = deriveType(scope, call); @@ -5694,7 +5771,7 @@ protected void validateFeature( public SqlNode expandSelectExpr(SqlNode expr, SelectScope scope, SqlSelect select) { final Expander expander = new SelectExpander(this, scope, select); - final SqlNode newExpr = expr.accept(expander); + final SqlNode newExpr = expander.go(expr); if (expr != newExpr) { setOriginal(newExpr, expr); } @@ -5703,7 +5780,7 @@ public SqlNode expandSelectExpr(SqlNode expr, @Override public SqlNode expand(SqlNode expr, SqlValidatorScope scope) { final Expander expander = new Expander(this, scope); - SqlNode newExpr = expr.accept(expander); + SqlNode newExpr = expander.go(expr); if (expr != newExpr) { setOriginal(newExpr, expr); } @@ -5714,7 +5791,7 @@ public SqlNode expandGroupByOrHavingExpr(SqlNode expr, SqlValidatorScope scope, SqlSelect select, boolean havingExpression) { final Expander expander = new ExtendedExpander(this, scope, select, expr, havingExpression); - SqlNode newExpr = expr.accept(expander); + SqlNode newExpr = expander.go(expr); if (expr != newExpr) { setOriginal(newExpr, expr); } @@ -5744,13 +5821,15 @@ public SqlNode expandGroupByOrHavingExpr(SqlNode expr, private @Nullable List getFieldOrigin(SqlNode sqlQuery, int i) { if (sqlQuery instanceof SqlSelect) { SqlSelect sqlSelect = (SqlSelect) sqlQuery; - final SelectScope scope = getRawSelectScope(sqlSelect); - final List selectList = scope.getExpandedSelectList(); + final SelectScope scope = getRawSelectScopeNonNull(sqlSelect); + final List selectList = requireNonNull(scope.getExpandedSelectList(), + () -> "expandedSelectList for " + scope); final SqlNode selectItem = stripAs(selectList.get(i)); if (selectItem instanceof SqlIdentifier) { final SqlQualified qualified = scope.fullyQualify((SqlIdentifier) selectItem); - SqlValidatorNamespace namespace = qualified.namespace; + SqlValidatorNamespace namespace = requireNonNull(qualified.namespace, + () -> "namespace for " + qualified); final SqlValidatorTable table = namespace.getTable(); if (table == null) { return null; @@ -6102,7 +6181,12 @@ private static class Expander extends SqlScopedShuttle { this.validator = validator; } - @Override public SqlNode visit(SqlIdentifier id) { + public SqlNode go(SqlNode root) { + return requireNonNull(root.accept(this), + () -> this + " returned null for " + root); + } + + @Override public @Nullable SqlNode visit(SqlIdentifier id) { // First check for builtin functions which don't have // parentheses, like "LOCALTIME". final SqlCall call = validator.makeNullaryCall(id); @@ -6127,7 +6211,7 @@ private static class Expander extends SqlScopedShuttle { } // Only visits arguments which are expressions. We don't want to // qualify non-expressions such as 'x' in 'empno * 5 AS x'. - ArgHandler argHandler = + CallCopyingArgHandler argHandler = new CallCopyingArgHandler(call, false); call.getOperator().acceptCall(this, call, true, argHandler); final SqlNode result = argHandler.result(); @@ -6167,14 +6251,15 @@ class OrderExpressionExpander extends SqlScopedShuttle { super(getOrderScope(select)); this.select = select; this.root = root; - this.aliasList = getNamespace(select).getRowType().getFieldNames(); + this.aliasList = getNamespaceOrThrow(select).getRowType().getFieldNames(); } public SqlNode go() { - return root.accept(this); + return requireNonNull(root.accept(this), + () -> "OrderExpressionExpander returned null for " + root); } - @Override public SqlNode visit(SqlLiteral literal) { + @Override public @Nullable SqlNode visit(SqlLiteral literal) { // Ordinal markers, e.g. 'select a, b from t order by 2'. // Only recognize them if they are the whole expression, // and if the dialect permits. @@ -6212,7 +6297,7 @@ private SqlNode nthSelectItem(int ordinal, final SqlParserPos pos) { SqlNodeList expandedSelectList = expandStar( - select.getSelectList(), + SqlNonNullableAccessors.getSelectList(select), select, false); SqlNode expr = expandedSelectList.get(ordinal); @@ -6231,7 +6316,7 @@ private SqlNode nthSelectItem(int ordinal, final SqlParserPos pos) { if (id.isSimple() && config.sqlConformance().isSortByAlias()) { String alias = id.getSimple(); - final SqlValidatorNamespace selectNs = getNamespace(select); + final SqlValidatorNamespace selectNs = getNamespaceOrThrow(select); final RelDataType rowType = selectNs.getRowTypeSansSystemColumns(); final SqlNameMatcher nameMatcher = catalogReader.nameMatcher(); @@ -6247,7 +6332,7 @@ private SqlNode nthSelectItem(int ordinal, final SqlParserPos pos) { return getScope().fullyQualify(id).identifier; } - @Override protected SqlNode visitScoped(SqlCall call) { + @Override protected @Nullable SqlNode visitScoped(SqlCall call) { // Don't attempt to expand sub-queries. We haven't implemented // these yet. if (call instanceof SqlSelect) { @@ -6271,7 +6356,7 @@ static class SelectExpander extends Expander { this.select = select; } - @Override public SqlNode visit(SqlIdentifier id) { + @Override public @Nullable SqlNode visit(SqlIdentifier id) { final SqlNode node = expandCommonColumn(select, id, (SelectScope) getScope(), validator); if (node != id) { return node; @@ -6298,7 +6383,7 @@ static class ExtendedExpander extends Expander { this.havingExpr = havingExpr; } - @Override public SqlNode visit(SqlIdentifier id) { + @Override public @Nullable SqlNode visit(SqlIdentifier id) { if (id.isSimple() && (havingExpr ? validator.config().sqlConformance().isHavingAlias() @@ -6308,7 +6393,7 @@ static class ExtendedExpander extends Expander { final SqlNameMatcher nameMatcher = validator.catalogReader.nameMatcher(); int n = 0; - for (SqlNode s : select.getSelectList()) { + for (SqlNode s : SqlNonNullableAccessors.getSelectList(select)) { final String alias = SqlValidatorUtil.getAlias(s, -1); if (alias != null && nameMatcher.matches(alias, name)) { expr = s; @@ -6343,7 +6428,7 @@ static class ExtendedExpander extends Expander { return super.visit(id); } - @Override public SqlNode visit(SqlLiteral literal) { + @Override public @Nullable SqlNode visit(SqlLiteral literal) { if (havingExpr || !validator.config().sqlConformance().isGroupByOrdinal()) { return super.visit(literal); } @@ -6371,14 +6456,14 @@ static class ExtendedExpander extends Expander { case DOUBLE: final int intValue = literal.intValue(false); if (intValue >= 0) { - if (intValue < 1 || intValue > select.getSelectList().size()) { + if (intValue < 1 || intValue > SqlNonNullableAccessors.getSelectList(select).size()) { throw validator.newValidationError(literal, RESOURCE.orderByOrdinalOutOfRange()); } // SQL ordinals are 1-based, but Sort's are 0-based int ordinal = intValue - 1; - return SqlUtil.stripAs(select.getSelectList().get(ordinal)); + return SqlUtil.stripAs(SqlNonNullableAccessors.getSelectList(select).get(ordinal)); } break; default: @@ -6431,7 +6516,8 @@ public FunctionParamInfo() { */ private static class NavigationModifier extends SqlShuttle { public SqlNode go(SqlNode node) { - return node.accept(this); + return requireNonNull(node.accept(this), + () -> "NavigationModifier returned for " + node); } } @@ -6460,10 +6546,10 @@ private static class NavigationExpander extends NavigationModifier { this.op = operator; } - @Override public SqlNode visit(SqlCall call) { + @Override public @Nullable SqlNode visit(SqlCall call) { SqlKind kind = call.getKind(); List operands = call.getOperandList(); - List newOperands = new ArrayList<>(); + List<@Nullable SqlNode> newOperands = new ArrayList<>(); if (call.getFunctionQuantifier() != null && call.getFunctionQuantifier().getValue() == SqlSelectKeyword.DISTINCT) { @@ -6549,7 +6635,7 @@ private static class NavigationReplacer extends NavigationModifier { this.alpha = alpha; } - @Override public SqlNode visit(SqlCall call) { + @Override public @Nullable SqlNode visit(SqlCall call) { SqlKind kind = call.getKind(); if (isLogicalNavigation(kind) || isAggregation(kind) @@ -6806,9 +6892,10 @@ public void permute(List selectItems, final RelDataType type1 = field1.getValue(); // output is nullable only if both inputs are final boolean nullable = type.isNullable() && type1.isNullable(); - final RelDataType type2 = - SqlTypeUtil.leastRestrictiveForComparison(typeFactory, type, - type1); + RelDataType currentType = type; + final RelDataType type2 = requireNonNull( + SqlTypeUtil.leastRestrictiveForComparison(typeFactory, type, type1), + () -> "leastRestrictiveForComparison for types " + currentType + " and " + type1); selectItem = SqlStdOperatorTable.AS.createCall(SqlParserPos.ZERO, SqlStdOperatorTable.COALESCE.createCall(SqlParserPos.ZERO, 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 3e5085c23285..735345a54b85 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 @@ -173,7 +173,7 @@ public interface SqlValidatorNamespace { * @return This namespace cast to desired type * @throws ClassCastException if no such interface is available */ - T unwrap(Class clazz); + T unwrap(Class clazz); /** * Returns whether this namespace implements a given interface, or wraps a 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 7fc7441a9eb4..97ff58a38dd9 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 @@ -74,13 +74,16 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Properties; import java.util.Set; import java.util.TreeSet; +import static org.apache.calcite.sql.type.NonNullableAccessors.getCharset; +import static org.apache.calcite.sql.type.NonNullableAccessors.getCollation; import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * Utility methods related to validation. */ @@ -103,13 +106,14 @@ private SqlValidatorUtil() {} */ public static @Nullable RelOptTable getRelOptTable( SqlValidatorNamespace namespace, - Prepare.CatalogReader catalogReader, + Prepare.@Nullable CatalogReader catalogReader, @Nullable String datasetName, boolean @Nullable [] usedDataset) { if (namespace.isWrapperFor(TableNamespace.class)) { final TableNamespace tableNamespace = namespace.unwrap(TableNamespace.class); - return getRelOptTable(tableNamespace, catalogReader, datasetName, usedDataset, + return getRelOptTable(tableNamespace, + requireNonNull(catalogReader, "catalogReader"), datasetName, usedDataset, tableNamespace.extendedFields); } else if (namespace.isWrapperFor(SqlValidatorImpl.DmlNamespace.class)) { final SqlValidatorImpl.DmlNamespace dmlNamespace = namespace.unwrap( @@ -122,7 +126,8 @@ private SqlValidatorUtil() {} ? ImmutableList.of() : getExtendedColumns(namespace.getValidator(), validatorTable, dmlNamespace.extendList); return getRelOptTable( - tableNamespace, catalogReader, datasetName, usedDataset, extendedFields); + tableNamespace, requireNonNull(catalogReader, "catalogReader"), + datasetName, usedDataset, extendedFields); } } return null; @@ -169,7 +174,7 @@ public static List getExtendedColumns( extendedFields.add( new RelDataTypeFieldImpl(identifier.toString(), extendedFieldOffset++, - type.deriveType(Objects.requireNonNull(validator, "validator")))); + type.deriveType(requireNonNull(validator, "validator")))); } return extendedFields.build(); } @@ -255,10 +260,8 @@ public static void checkCharsetAndCollateConsistentIfCharType( RelDataType type) { // (every charset must have a default collation) if (SqlTypeUtil.inCharFamily(type)) { - Charset strCharset = type.getCharset(); - Charset colCharset = type.getCollation().getCharset(); - assert null != strCharset; - assert null != colCharset; + Charset strCharset = getCharset(type); + Charset colCharset = getCollation(type).getCharset(); if (!strCharset.equals(colCharset)) { if (false) { // todo: enable this checking when we have a charset to @@ -490,7 +493,7 @@ public static RelDataType deriveJoinRowType( switch (joinType) { case LEFT: rightType = typeFactory.createTypeWithNullability( - Objects.requireNonNull(rightType, "rightType"), true); + requireNonNull(rightType, "rightType"), true); break; case RIGHT: leftType = typeFactory.createTypeWithNullability(leftType, true); @@ -498,7 +501,7 @@ public static RelDataType deriveJoinRowType( case FULL: leftType = typeFactory.createTypeWithNullability(leftType, true); rightType = typeFactory.createTypeWithNullability( - Objects.requireNonNull(rightType, "rightType"), true); + requireNonNull(rightType, "rightType"), true); break; case SEMI: case ANTI: @@ -892,7 +895,7 @@ private static ImmutableBitSet analyzeGroupExpr(SqlValidatorScope scope, } } - RelDataTypeField field = Objects.requireNonNull( + RelDataTypeField field = requireNonNull( nameMatcher.field(rowType, originalFieldName), () -> "field " + originalFieldName + " is not found in " + rowType + " with " + nameMatcher); @@ -1178,7 +1181,7 @@ public static Pair validateExprWithRowType( typeFactory, SqlValidator.Config.DEFAULT); final SqlSelect select = (SqlSelect) validator.validate(select0); - SqlNodeList selectList = Objects.requireNonNull( + SqlNodeList selectList = requireNonNull( select.getSelectList(), () -> "selectList in " + select); assert selectList.size() == 1 @@ -1327,7 +1330,7 @@ private static class ExplicitRowTypeTable extends AbstractTable { private final RelDataType rowType; ExplicitRowTypeTable(RelDataType rowType) { - this.rowType = Objects.requireNonNull(rowType); + this.rowType = requireNonNull(rowType); } @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) { @@ -1342,7 +1345,7 @@ private static class ExplicitTableSchema extends AbstractSchema { private final Map tableMap; ExplicitTableSchema(Map tableMap) { - this.tableMap = Objects.requireNonNull(tableMap); + this.tableMap = requireNonNull(tableMap); } @Override protected Map getTableMap() { 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 d2095a213270..b8571d022ff7 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 @@ -38,7 +38,7 @@ class WithItemNamespace extends AbstractNamespace { @Override protected RelDataType validateImpl(RelDataType targetRowType) { final SqlValidatorNamespace childNs = - validator.getNamespace(withItem.query); + validator.getNamespaceOrThrow(withItem.query); final RelDataType rowType = childNs.getRowTypeSansSystemColumns(); if (withItem.columnList == null) { return rowType; @@ -64,7 +64,7 @@ class WithItemNamespace extends AbstractNamespace { final RelDataType underlyingRowType = validator.getValidatedNodeType(withItem.query); int i = 0; - for (RelDataTypeField field : rowType.getFieldList()) { + for (RelDataTypeField field : getRowType().getFieldList()) { if (field.getName().equals(name)) { return underlyingRowType.getFieldList().get(i).getName(); } 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 c3be0a58ff82..cd6688440a9d 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 @@ -48,7 +48,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Objects; + +import static org.apache.calcite.sql.type.NonNullableAccessors.getCollation; + +import static java.util.Objects.requireNonNull; /** * Base class for all the type coercion rules. If you want to have a custom type coercion rules, @@ -73,8 +76,8 @@ public abstract class AbstractTypeCoercion implements TypeCoercion { //~ Constructors ----------------------------------------------------------- AbstractTypeCoercion(RelDataTypeFactory typeFactory, SqlValidator validator) { - this.factory = Objects.requireNonNull(typeFactory); - this.validator = Objects.requireNonNull(validator); + this.factory = requireNonNull(typeFactory); + this.validator = requireNonNull(validator); } //~ Methods ---------------------------------------------------------------- @@ -84,7 +87,7 @@ public abstract class AbstractTypeCoercion implements TypeCoercion { * we do this base on the fact that validate happens before type coercion. */ protected boolean coerceOperandType( - SqlValidatorScope scope, + @Nullable SqlValidatorScope scope, SqlCall call, int index, RelDataType targetType) { @@ -99,6 +102,7 @@ protected boolean coerceOperandType( // Do not support implicit type coercion for dynamic param. return false; } + requireNonNull(scope, "scope"); // Check it early. if (!needToCast(scope, operand, targetType)) { return false; @@ -138,7 +142,7 @@ protected boolean coerceOperandsType( * @param targetType Target type to cast to */ protected boolean coerceColumnType( - SqlValidatorScope scope, + @Nullable SqlValidatorScope scope, SqlNodeList nodeList, int index, RelDataType targetType) { @@ -177,6 +181,7 @@ protected boolean coerceColumnType( } } + requireNonNull(scope, "scope is needed for needToCast(scope, operand, targetType)"); if (node instanceof SqlCall) { SqlCall node2 = (SqlCall) node; if (node2.getOperator().kind == SqlKind.AS) { @@ -214,8 +219,8 @@ RelDataType syncAttributes( if (SqlTypeUtil.inCharOrBinaryFamilies(fromType) && SqlTypeUtil.inCharOrBinaryFamilies(toType)) { Charset charset = fromType.getCharset(); - SqlCollation collation = fromType.getCollation(); if (charset != null && SqlTypeUtil.inCharFamily(syncedType)) { + SqlCollation collation = getCollation(fromType); syncedType = factory.createTypeWithCharsetAndCollation(syncedType, charset, collation); 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 740b3e50fd3d..04c3536b9672 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 @@ -109,7 +109,7 @@ public interface TypeCoercion { * @param targetType Target type to cast to */ boolean rowTypeCoercion( - SqlValidatorScope scope, + @Nullable SqlValidatorScope scope, SqlNode query, int columnIndex, RelDataType targetType); @@ -189,6 +189,6 @@ boolean userDefinedFunctionCoercion(SqlValidatorScope scope, SqlCall call, * @param targetRowType Target row type * @param query The query, either an INSERT or UPDATE */ - boolean querySourceCoercion(SqlValidatorScope scope, + boolean querySourceCoercion(@Nullable SqlValidatorScope scope, RelDataType sourceRowType, RelDataType targetRowType, SqlNode query); } diff --git a/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java index a602337fe99f..a0d1c757801b 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/implicit/TypeCoercionImpl.java @@ -41,6 +41,8 @@ import org.apache.calcite.sql.validate.SqlValidatorScope; import org.apache.calcite.util.Util; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.math.BigDecimal; import java.util.AbstractList; import java.util.ArrayList; @@ -48,6 +50,10 @@ import java.util.List; import java.util.stream.Collectors; +import static org.apache.calcite.sql.validate.SqlNonNullableAccessors.getSelectList; + +import static java.util.Objects.requireNonNull; + /** * Default implementation of Calcite implicit type cast. */ @@ -80,7 +86,7 @@ public TypeCoercionImpl(RelDataTypeFactory typeFactory, SqlValidator validator) * @param targetType Target type to cast to */ @Override public boolean rowTypeCoercion( - SqlValidatorScope scope, + @Nullable SqlValidatorScope scope, SqlNode query, int columnIndex, RelDataType targetType) { @@ -89,7 +95,7 @@ public TypeCoercionImpl(RelDataTypeFactory typeFactory, SqlValidator validator) case SELECT: SqlSelect selectNode = (SqlSelect) query; SqlValidatorScope scope1 = validator.getSelectScope(selectNode); - if (!coerceColumnType(scope1, selectNode.getSelectList(), columnIndex, targetType)) { + if (!coerceColumnType(scope1, getSelectList(selectNode), columnIndex, targetType)) { return false; } updateInferredColumnType(scope1, query, columnIndex, targetType); @@ -100,7 +106,8 @@ public TypeCoercionImpl(RelDataTypeFactory typeFactory, SqlValidator validator) return false; } } - updateInferredColumnType(scope, query, columnIndex, targetType); + updateInferredColumnType( + requireNonNull(scope, "scope"), query, columnIndex, targetType); return true; case WITH: SqlNode body = ((SqlWith) query).body; @@ -115,7 +122,8 @@ public TypeCoercionImpl(RelDataTypeFactory typeFactory, SqlValidator validator) && rowTypeCoercion(scope, operand1, columnIndex, targetType); // Update the nested SET operator node type. if (coerced) { - updateInferredColumnType(scope, query, columnIndex, targetType); + updateInferredColumnType( + requireNonNull(scope, "scope"), query, columnIndex, targetType); } return coerced; default: @@ -259,7 +267,7 @@ protected boolean binaryArithmeticWithStrings( * For operand data types (type1, type2, type3), deduce the common type type4 * from type1 and type2, then common type type5 from type4 and type3. */ - protected RelDataType commonTypeForComparison(List dataTypes) { + protected @Nullable RelDataType commonTypeForComparison(List dataTypes) { assert dataTypes.size() > 2; final RelDataType type1 = dataTypes.get(0); final RelDataType type2 = dataTypes.get(1); @@ -591,7 +599,7 @@ && coerceOperandType(binding.getScope(), binding.getCall(), i, implicitType) return coerced; } - @Override public boolean querySourceCoercion(SqlValidatorScope scope, + @Override public boolean querySourceCoercion(@Nullable SqlValidatorScope scope, RelDataType sourceRowType, RelDataType targetRowType, SqlNode query) { final List sourceFields = sourceRowType.getFieldList(); final List targetFields = targetRowType.getFieldList(); @@ -623,7 +631,7 @@ && coerceOperandType(binding.getScope(), binding.getCall(), i, implicitType) * @param targetType Target type */ private boolean coerceSourceRowType( - SqlValidatorScope sourceScope, + @Nullable SqlValidatorScope sourceScope, SqlNode query, int columnIndex, RelDataType targetType) { diff --git a/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java b/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java index 8992f04890d7..13ac72c37ba1 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java @@ -23,6 +23,8 @@ import org.apache.calcite.schema.ColumnStrategy; import org.apache.calcite.sql.SqlFunction; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import java.util.function.BiFunction; @@ -61,7 +63,8 @@ public NullInitializerExpressionFactory() { return context.getRexBuilder().makeNullLiteral(fieldType); } - @Override public BiFunction postExpressionConversionHook() { + @Override public @Nullable BiFunction< + InitializerContext, RelNode, RelNode> postExpressionConversionHook() { return null; } diff --git a/core/src/main/java/org/apache/calcite/sql2rel/ReflectiveConvertletTable.java b/core/src/main/java/org/apache/calcite/sql2rel/ReflectiveConvertletTable.java index d7010f98cc74..e8f0040ce955 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/ReflectiveConvertletTable.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/ReflectiveConvertletTable.java @@ -25,6 +25,7 @@ import com.google.common.base.Preconditions; import org.checkerframework.checker.initialization.qual.UnderInitialization; +import org.checkerframework.checker.nullness.qual.Nullable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -32,6 +33,8 @@ import java.util.HashMap; import java.util.Map; +import static java.util.Objects.requireNonNull; + /** * Implementation of {@link SqlRexConvertletTable} which uses reflection to call * any method of the form public RexNode convertXxx(ConvertletContext, @@ -82,8 +85,10 @@ private void registerNodeTypeMethod(final Method method) { } map.put(parameterType, (SqlRexConvertlet) (cx, call) -> { try { - return (RexNode) method.invoke(ReflectiveConvertletTable.this, + RexNode result = (RexNode) method.invoke(ReflectiveConvertletTable.this, cx, call); + return requireNonNull(result, () -> "null result from " + method + + " for call " + call); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException("while converting " + call, e); } @@ -123,15 +128,17 @@ private void registerOpTypeMethod(final Method method) { } map.put(opClass, (SqlRexConvertlet) (cx, call) -> { try { - return (RexNode) method.invoke(ReflectiveConvertletTable.this, + RexNode result = (RexNode) method.invoke(ReflectiveConvertletTable.this, cx, call.getOperator(), call); + return requireNonNull(result, () -> "null result from " + method + + " for call " + call); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException("while converting " + call, e); } }); } - @Override public SqlRexConvertlet get(SqlCall call) { + @Override public @Nullable SqlRexConvertlet get(SqlCall call) { SqlRexConvertlet convertlet; final SqlOperator op = call.getOperator(); diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java b/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java index a70e1a470034..b31286d09145 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java @@ -91,9 +91,12 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.SortedMap; import java.util.SortedSet; +import static java.util.Objects.requireNonNull; + // TODO jvs 10-Feb-2005: factor out generic rewrite helper, with the // ability to map between old and new rels and field ordinals. Also, // for now need to prohibit queries which return UDT instances. @@ -140,7 +143,7 @@ public class RelStructuredTypeFlattener implements ReflectiveVisitor { private final boolean restructure; private final Map oldToNewRelMap = new HashMap<>(); - private RelNode currentRel; + private @Nullable RelNode currentRel; private int iRestructureInput; @SuppressWarnings("unused") private RelDataType flattenedRootType; @@ -269,7 +272,9 @@ protected void setNewForOldRel(RelNode oldRel, RelNode newRel) { } protected RelNode getNewForOldRel(RelNode oldRel) { - return oldToNewRelMap.get(oldRel); + return requireNonNull( + oldToNewRelMap.get(oldRel), + () -> "newRel not found for " + oldRel); } /** @@ -595,7 +600,7 @@ public void rewriteGeneric(RelNode rel) { private void flattenProjections(RewriteRexShuttle shuttle, List exps, - List fieldNames, + @Nullable List fieldNames, String prefix, List> flattenedExps) { for (int i = 0; i < exps.size(); ++i) { @@ -605,7 +610,7 @@ private void flattenProjections(RewriteRexShuttle shuttle, } } - private String extractName(List fieldNames, String prefix, int i) { + private String extractName(@Nullable List fieldNames, String prefix, int i) { String fieldName = (fieldNames == null || fieldNames.get(i) == null) ? ("$" + i) : fieldNames.get(i); @@ -665,7 +670,8 @@ private void flattenProjection(RewriteRexShuttle shuttle, // why we're trying to get range from to. For primitive just one field will be in range. int from = 0; for (RelDataTypeField field : firstOp.getType().getFieldList()) { - if (literalString.equalsIgnoreCase(field.getName())) { + if (Objects.equals(literalString, field.getName()) + || String.CASE_INSENSITIVE_ORDER.compare(literalString, field.getName()) == 0) { int oldOrdinal = ((RexInputRef) firstOp).getIndex(); int to = from + postFlattenSize(field.getType()); for (int newInnerOrdinal = from; newInnerOrdinal < to; newInnerOrdinal++) { @@ -992,7 +998,7 @@ private RelDataType removeDistinct(RelDataType type) { return subQuery.clone(rel); } - private RexNode flattenComparison( + private @Nullable RexNode flattenComparison( RexBuilder rexBuilder, SqlOperator op, List exprs) { diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlRexConvertletTable.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlRexConvertletTable.java index db96cddd59ad..92562019c327 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/SqlRexConvertletTable.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlRexConvertletTable.java @@ -18,6 +18,8 @@ import org.apache.calcite.sql.SqlCall; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Collection of {@link SqlRexConvertlet}s. */ @@ -27,5 +29,5 @@ public interface SqlRexConvertletTable { /** * Returns the convertlet applicable to a given expression. */ - SqlRexConvertlet get(SqlCall call); + @Nullable SqlRexConvertlet get(SqlCall call); } 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 b69d720afd72..6a7749da8e79 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java @@ -359,7 +359,7 @@ private T getNamespace(SqlNode node) { @SuppressWarnings("unchecked") private @Nullable T getNamespaceOrNull(SqlNode node) { - return (T) validator().getNamespace(node); + return (@Nullable T) validator().getNamespace(node); } /** Returns the RelOptCluster in use. */ @@ -1493,12 +1493,10 @@ public RelNode convertToSingleValueSubq( // If there is a limit with 0 or 1, // it is ensured to produce a single value - if (select.getFetch() != null - && select.getFetch() instanceof SqlNumericLiteral) { - SqlNumericLiteral limitNum = (SqlNumericLiteral) select.getFetch(); - BigDecimal value = (BigDecimal) limitNum.getValue(); - requireNonNull(value, () -> "limit is null in " + select); - if (value.intValue() < 2) { + SqlNode fetch = select.getFetch(); + if (fetch instanceof SqlNumericLiteral) { + long value = ((SqlNumericLiteral) fetch).getValueAs(Long.class); + if (value < 2) { return plan; } } @@ -2440,13 +2438,13 @@ protected void convertMatchRecognize(Blackboard bb, } protected void convertPivot(Blackboard bb, SqlPivot pivot) { - final SqlValidatorScope scope = validator.getJoinScope(pivot); + final SqlValidatorScope scope = validator().getJoinScope(pivot); final Blackboard pivotBb = createBlackboard(scope, null, false); // Convert input convertFrom(pivotBb, pivot.query); - final RelNode input = pivotBb.root; + final RelNode input = pivotBb.root(); final RelDataType inputRowType = input.getRowType(); relBuilder.push(input); @@ -2468,7 +2466,7 @@ protected void convertPivot(Blackboard bb, SqlPivot pivot) { // 3. Gather columns used as arguments to aggregate functions. pivotBb.agg = aggConverter; - final List aggAliasList = new ArrayList<>(); + final List<@Nullable String> aggAliasList = new ArrayList<>(); assert aggConverter.aggCalls.size() == 0; pivot.forEachAgg((alias, call) -> { call.accept(aggConverter); @@ -2812,8 +2810,9 @@ protected RelNode createJoin( if (exprProjection != null) { // sub-query can reference group by keys projected from // the root of the outer relation. - if (exprProjection.containsKey(pos)) { - pos = exprProjection.get(pos); + Integer projection = exprProjection.get(pos); + if (projection != null) { + pos = projection; } else { // correl not grouped throw new AssertionError("Identifier '" + originalRelName + "." @@ -2913,16 +2912,16 @@ private void convertJoin(Blackboard bb, SqlJoin join) { final Blackboard rightBlackboard = createBlackboard(rightScope, null, false); convertFrom(leftBlackboard, left); - final RelNode leftRel = leftBlackboard.root; + final RelNode leftRel = requireNonNull(leftBlackboard.root, "leftBlackboard.root"); convertFrom(rightBlackboard, right); - final RelNode tempRightRel = rightBlackboard.root; + final RelNode tempRightRel = requireNonNull(rightBlackboard.root, "rightBlackboard.root"); final JoinConditionType conditionType = join.getConditionType(); final RexNode condition; final RelNode rightRel; if (join.isNatural()) { - condition = convertNaturalCondition(validator.getNamespace(left), - validator.getNamespace(right)); + condition = convertNaturalCondition(getNamespace(left), + getNamespace(right)); rightRel = tempRightRel; } else { switch (conditionType) { @@ -2932,8 +2931,8 @@ private void convertJoin(Blackboard bb, SqlJoin join) { break; case USING: condition = convertUsingCondition(join, - validator.getNamespace(left), - validator.getNamespace(right)); + getNamespace(left), + getNamespace(right)); rightRel = tempRightRel; break; case ON: @@ -2972,7 +2971,8 @@ private RexNode convertUsingCondition( SqlJoin join, SqlValidatorNamespace leftNamespace, SqlValidatorNamespace rightNamespace) { - SqlNode condition = join.getCondition(); + SqlNode condition = requireNonNull(join.getCondition(), + () -> "getCondition for join " + join); final SqlNodeList list = (SqlNodeList) condition; final List nameList = new ArrayList<>(); @@ -3014,7 +3014,8 @@ private Pair convertOnCondition( SqlJoin join, RelNode leftRel, RelNode rightRel) { - SqlNode condition = join.getCondition(); + SqlNode condition = requireNonNull(join.getCondition(), + () -> "getCondition for join " + join); bb.setRoot(ImmutableList.of(leftRel, rightRel)); replaceSubQueries(bb, condition, RelOptUtil.Logic.UNKNOWN_AS_FALSE); @@ -3152,7 +3153,9 @@ protected final void createAggImpl( // Calcite allows expressions, not just column references in // group by list. This is not SQL 2003 compliant, but hey. - final AggregatingSelectScope scope = aggConverter.aggregatingSelectScope; + final AggregatingSelectScope scope = requireNonNull( + aggConverter.aggregatingSelectScope, + "aggregatingSelectScope"); final AggregatingSelectScope.Resolved r = scope.resolved.get(); for (SqlNode groupExpr : r.groupExprList) { aggConverter.addGroupExpr(groupExpr); @@ -3768,8 +3771,12 @@ protected RelNode convertColumnList(final SqlInsert call, RelNode source) { } } + // sourceExps should not contain nulls (see the loop above) + @SuppressWarnings("assignment.type.incompatible") + List nonNullExprs = sourceExps; + return relBuilder.push(source) - .projectNamed(sourceExps, fieldNames, false) + .projectNamed(nonNullExprs, fieldNames, false) .build(); } @@ -3811,7 +3818,7 @@ private InitializerExpressionFactory getInitializerFactory( return NullInitializerExpressionFactory.INSTANCE; } - private static @Nullable T unwrap(@Nullable Object o, Class clazz) { + private static @Nullable T unwrap(@Nullable Object o, Class clazz) { if (o instanceof Wrapper) { return ((Wrapper) o).unwrap(clazz); } @@ -4005,6 +4012,7 @@ private RelNode convertMerge(SqlMerge call) { int nSourceFields = join.getLeft().getRowType().getFieldCount(); final List projects = new ArrayList<>(); for (int level1Idx = 0; level1Idx < nLevel1Exprs; level1Idx++) { + requireNonNull(level1InsertExprs, "level1InsertExprs"); if ((level2InsertExprs != null) && (level1InsertExprs.get(level1Idx) instanceof RexInputRef)) { int level2Idx = @@ -4052,11 +4060,15 @@ private RexNode convertIdentifier( } else { qualified = SqlQualified.create(null, 1, null, identifier); } - final Pair> e0 = bb.lookupExp(qualified); + final Pair> e0 = requireNonNull( + bb.lookupExp(qualified), + () -> "no expression found for " + qualified); RexNode e = e0.left; for (String name : qualified.suffix()) { if (e == e0.left && e0.right != null) { - int i = e0.right.get(name); + Integer i = requireNonNull( + e0.right.get(name), + () -> "e0.right.get(name) produced null for " + name); e = rexBuilder.makeFieldAccess(e, i); } else { final boolean caseSensitive = true; // name already fully-qualified @@ -4173,7 +4185,8 @@ private RelNode convertMultisets(final List operands, } RelDataType multisetType = validator().getValidatedNodeType(call); validator().setValidatedNodeType(list, - multisetType.getComponentType()); + requireNonNull(multisetType.getComponentType(), + () -> "componentType for multisetType " + multisetType)); input = convertQueryOrInList(usedBb, list, null); break; case MULTISET_QUERY_CONSTRUCTOR: @@ -4194,7 +4207,7 @@ private RelNode convertMultisets(final List operands, new Collect( cluster, cluster.traitSetOf(Convention.NONE), - input, + requireNonNull(input, "input"), castNonNull(validator().deriveAlias(call, i))); joinList.add(collect); } @@ -4251,7 +4264,9 @@ private void convertSelectList( Blackboard bb, SqlSelect select, List orderList) { - SqlNodeList selectList = select.getSelectList(); + SqlNodeList selectList = requireNonNull( + select.getSelectList(), + () -> "null selectList for " + select); selectList = validator().expandStar(selectList, select, false); replaceSubQueries(bb, selectList, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN); @@ -4359,7 +4374,7 @@ public RelNode convertValues( assert scope != null; final Blackboard bb = createBlackboard(scope, null, false); convertValuesImpl(bb, values, targetRowType); - return bb.root; + return bb.root(); } /** @@ -4431,9 +4446,9 @@ private void convertValuesImpl( private static class RegisterArgs { final RelNode rel; final JoinRelType joinType; - final List leftKeys; + final @Nullable List leftKeys; - RegisterArgs(RelNode rel, JoinRelType joinType, List leftKeys) { + RegisterArgs(RelNode rel, JoinRelType joinType, @Nullable List leftKeys) { this.rel = rel; this.joinType = joinType; this.leftKeys = leftKeys; @@ -4545,10 +4560,10 @@ public RexNode register( RelNode rel, JoinRelType joinType, @Nullable List leftKeys) { - assert joinType != null; + requireNonNull(joinType, "joinType"); registered.add(new RegisterArgs(rel, joinType, leftKeys)); if (root == null) { - assert leftKeys == null; + assert leftKeys == null : "leftKeys must be null"; setRoot(rel, false); return rexBuilder.makeRangeReference( root().getRowType(), @@ -4580,10 +4595,11 @@ public RexNode register( .build(); // maintain the group by mapping in the new LogicalProject - if (mapRootRelToFieldProjection.containsKey(root())) { + Map currentProjection = mapRootRelToFieldProjection.get(root()); + if (currentProjection != null) { mapRootRelToFieldProjection.put( newLeftInput, - mapRootRelToFieldProjection.get(root())); + currentProjection); } setRoot(newLeftInput, false); @@ -4660,7 +4676,7 @@ public RelNode reRegister(RelNode root) { for (RegisterArgs reg: registerCopy) { register(reg.rel, reg.joinType, reg.leftKeys); } - return this.root; + return requireNonNull(this.root, "root"); } /** @@ -4812,6 +4828,7 @@ RexNode lookup( } @Nullable RelDataTypeField getRootField(RexInputRef inputRef) { + List inputs = this.inputs; if (inputs == null) { return null; } @@ -4888,6 +4905,7 @@ ImmutableList retrieveCursors() { @Override public RexNode convertExpression(SqlNode expr) { // If we're in aggregation mode and this is an expression in the // GROUP BY clause, return a reference to the field. + AggConverter agg = this.agg; if (agg != null) { final SqlNode expandedGroupExpr = validator().expand(expr, scope()); final int ref = agg.lookupGroupExpr(expandedGroupExpr); @@ -5147,7 +5165,7 @@ private boolean isConvertedSubq(RexNode rex) { @Override public RexRangeRef getSubQueryExpr(SqlCall call) { final SubQuery subQuery = getSubQuery(call); assert subQuery != null; - return (RexRangeRef) subQuery.expr; + return (RexRangeRef) requireNonNull(subQuery.expr, () -> "subQuery.expr for " + call); } @Override public RelDataTypeFactory getTypeFactory() { @@ -5181,7 +5199,8 @@ public RexNode convertInterval(SqlIntervalQualifier intervalQualifier) { && (op.isAggregator() || op.getKind() == SqlKind.FILTER || op.getKind() == SqlKind.WITHIN_GROUP)) { - return agg.lookupAggregates(call); + return requireNonNull(agg.lookupAggregates(call), + () -> "agg.lookupAggregates for call " + call); } } return exprConverter.convertCall(this, @@ -5280,7 +5299,7 @@ private static class NoOpSubQueryConverter implements SubQueryConverter { */ protected class AggConverter implements SqlVisitor { private final Blackboard bb; - public final AggregatingSelectScope aggregatingSelectScope; + public final @Nullable AggregatingSelectScope aggregatingSelectScope; private final Map nameMap = new HashMap<>(); @@ -5318,7 +5337,7 @@ protected class AggConverter implements SqlVisitor { /** Whether we are directly inside a windowed aggregate. */ private boolean inOver = false; - AggConverter(Blackboard bb, AggregatingSelectScope aggregatingSelectScope) { + AggConverter(Blackboard bb, @Nullable AggregatingSelectScope aggregatingSelectScope) { this.bb = bb; this.aggregatingSelectScope = aggregatingSelectScope; } diff --git a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java index 57f16dec89b7..52ad855e9e6b 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java @@ -1510,7 +1510,7 @@ private static class TimestampAddConvertlet implements SqlRexConvertlet { // => timestamp + count * INTERVAL '1' UNIT final RexBuilder rexBuilder = cx.getRexBuilder(); final SqlLiteral unitLiteral = call.operand(0); - final TimeUnit unit = Objects.requireNonNull(unitLiteral.symbolValue(TimeUnit.class), "unit"); + final TimeUnit unit = unitLiteral.getValueAs(TimeUnit.class); RexNode interval2Add; SqlIntervalQualifier qualifier = new SqlIntervalQualifier(unit, null, unitLiteral.getParserPosition()); @@ -1542,7 +1542,7 @@ private static class TimestampDiffConvertlet implements SqlRexConvertlet { // => (t2 - t1) UNIT final RexBuilder rexBuilder = cx.getRexBuilder(); final SqlLiteral unitLiteral = call.operand(0); - TimeUnit unit = Objects.requireNonNull(unitLiteral.symbolValue(TimeUnit.class), "unit"); + TimeUnit unit = unitLiteral.getValueAs(TimeUnit.class); BigDecimal multiplier = BigDecimal.ONE; BigDecimal divider = BigDecimal.ONE; SqlTypeName sqlTypeName = unit == TimeUnit.NANOSECOND diff --git a/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java b/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java index 760a9387eb95..40844f3b7939 100644 --- a/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java +++ b/core/src/main/java/org/apache/calcite/tools/FrameworkConfig.java @@ -96,7 +96,7 @@ public interface FrameworkConfig { * Returns the cost factory that should be used when creating the planner. * If null, use the default cost factory for that planner. */ - RelOptCostFactory getCostFactory(); + @Nullable RelOptCostFactory getCostFactory(); /** * Returns a list of trait definitions. diff --git a/core/src/main/java/org/apache/calcite/tools/Frameworks.java b/core/src/main/java/org/apache/calcite/tools/Frameworks.java index e55dfb798129..fcea840e9457 100644 --- a/core/src/main/java/org/apache/calcite/tools/Frameworks.java +++ b/core/src/main/java/org/apache/calcite/tools/Frameworks.java @@ -449,7 +449,7 @@ static class StdFrameworkConfig implements FrameworkConfig { return programs; } - @Override public RelOptCostFactory getCostFactory() { + @Override public @Nullable RelOptCostFactory getCostFactory() { return costFactory; } diff --git a/core/src/main/java/org/apache/calcite/tools/Hoist.java b/core/src/main/java/org/apache/calcite/tools/Hoist.java index aac81321319f..6265ee2386c1 100644 --- a/core/src/main/java/org/apache/calcite/tools/Hoist.java +++ b/core/src/main/java/org/apache/calcite/tools/Hoist.java @@ -30,6 +30,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.sql.PreparedStatement; import java.util.ArrayList; import java.util.List; @@ -107,7 +109,7 @@ public Hoisted hoist(String sql) { throw new RuntimeException(e); } node.accept(new SqlShuttle() { - @Override public SqlNode visit(SqlLiteral literal) { + @Override public @Nullable SqlNode visit(SqlLiteral literal) { variables.add(new Variable(sql, variables.size(), literal)); return super.visit(literal); } diff --git a/core/src/main/java/org/apache/calcite/tools/PigRelBuilder.java b/core/src/main/java/org/apache/calcite/tools/PigRelBuilder.java index f45a533a2ff6..e11bac273fb0 100644 --- a/core/src/main/java/org/apache/calcite/tools/PigRelBuilder.java +++ b/core/src/main/java/org/apache/calcite/tools/PigRelBuilder.java @@ -35,6 +35,8 @@ import java.util.ArrayList; import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Extension to {@link RelBuilder} for Pig relational operators. */ @@ -142,7 +144,7 @@ public PigRelBuilder group(GroupOption option, Partitioner partitioner, aggregate(groupKey.e, aggregateCall(SqlStdOperatorTable.COLLECT, row).as(getAlias())); if (groupKey.i < n - 1) { - push(r); + push(requireNonNull(r, "r")); List predicates = new ArrayList<>(); for (int key : Util.range(groupCount)) { predicates.add(equals(field(2, 0, key), field(2, 1, key))); @@ -171,7 +173,8 @@ protected void validateGroupList(List groupKeyList) { } else { RelNode top = peek(); if (top instanceof TableScan) { - return Util.last(top.getTable().getQualifiedName()); + TableScan scan = (TableScan) top; + return Util.last(scan.getTable().getQualifiedName()); } else { return null; } diff --git a/core/src/main/java/org/apache/calcite/tools/Programs.java b/core/src/main/java/org/apache/calcite/tools/Programs.java index 48d06380b1b7..dda92e0f4f1d 100644 --- a/core/src/main/java/org/apache/calcite/tools/Programs.java +++ b/core/src/main/java/org/apache/calcite/tools/Programs.java @@ -52,6 +52,8 @@ import java.util.Arrays; import java.util.List; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Utilities for creating {@link Program}s. */ @@ -238,9 +240,10 @@ public static Program subQuery(RelMetadataProvider metadataProvider) { return of(builder.build(), true, metadataProvider); } + @Deprecated public static Program getProgram() { return (planner, rel, requiredOutputTraits, materializations, lattices) -> - null; + castNonNull(null); } /** Returns the standard program used by Prepare. */ 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 b8c3fb3a115c..07dc85533450 100644 --- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java +++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java @@ -135,6 +135,8 @@ import static org.apache.calcite.linq4j.Nullness.castNonNull; import static org.apache.calcite.util.Static.RESOURCE; +import static java.util.Objects.requireNonNull; + /** * Builder for relational expressions. * @@ -170,7 +172,7 @@ protected RelBuilder(@Nullable Context context, RelOptCluster cluster, this.config = getConfig(context); this.viewExpander = getViewExpander(cluster, context); this.struct = - Objects.requireNonNull(RelFactories.Struct.fromContext(context)); + requireNonNull(RelFactories.Struct.fromContext(context)); final RexExecutor executor = Util.first(context.unwrap(RexExecutor.class), Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR)); @@ -475,8 +477,8 @@ public RexNode field(String alias, String fieldName) { * given alias. Searches for the relation starting at the top of the * stack. */ public RexNode field(int inputCount, String alias, String fieldName) { - Objects.requireNonNull(alias); - Objects.requireNonNull(fieldName); + requireNonNull(alias); + requireNonNull(fieldName); final List fields = new ArrayList<>(); for (int inputOrdinal = 0; inputOrdinal < inputCount; ++inputOrdinal) { final Frame frame = peek_(inputOrdinal); @@ -838,7 +840,7 @@ private GroupKey groupKey_(ImmutableBitSet groupSet, if (groupSet.length() > peek().getRowType().getFieldCount()) { throw new IllegalArgumentException("out of bounds: " + groupSet); } - Objects.requireNonNull(groupSets); + requireNonNull(groupSets); final ImmutableList nodes = fields(groupSet); return groupKey_(nodes, Util.transform(groupSets, bitSet -> fields(bitSet))); } @@ -1101,7 +1103,7 @@ public RexNode patternExclude(RexNode node) { */ public RelBuilder scan(Iterable tableNames) { final List names = ImmutableList.copyOf(tableNames); - Objects.requireNonNull(relOptSchema, "relOptSchema"); + requireNonNull(relOptSchema, "relOptSchema"); final RelOptTable relOptTable = relOptSchema.getTableForMember(names); if (relOptTable == null) { throw RESOURCE.tableNotFound(String.join(".", names)).ex(); @@ -1394,7 +1396,7 @@ private RelBuilder project_( Iterable fieldNames, Iterable hints, boolean force) { - final Frame frame = Objects.requireNonNull(peek_(), "frame stack is empty"); + final Frame frame = requireNonNull(peek_(), "frame stack is empty"); final RelDataType inputRowType = frame.rel.getRowType(); final List nodeList = Lists.newArrayList(nodes); @@ -1596,7 +1598,7 @@ public RelBuilder uncollect(List itemAliases, boolean withOrdinality) { cluster.traitSetOf(Convention.NONE), frame.rel, withOrdinality, - Objects.requireNonNull(itemAliases)))); + requireNonNull(itemAliases)))); return this; } @@ -1649,7 +1651,7 @@ public RelBuilder rename(List fieldNames) { switch (expr.getKind()) { case INPUT_REF: final RexInputRef ref = (RexInputRef) expr; - return Objects.requireNonNull(stack.peek(), "empty frame stack") + return requireNonNull(stack.peek(), "empty frame stack") .fields.get(ref.getIndex()).getValue().getName(); case CAST: return inferAlias(exprList, ((RexCall) expr).getOperands().get(0), -1); @@ -2083,7 +2085,7 @@ public RelBuilder transientScan(String tableName) { @Experimental public RelBuilder transientScan(String tableName, RelDataType rowType) { TransientTable transientTable = new ListTransientTable(tableName, rowType); - Objects.requireNonNull(relOptSchema, "relOptSchema"); + requireNonNull(relOptSchema, "relOptSchema"); RelOptTable relOptTable = RelOptTableImpl.create( relOptSchema, rowType, @@ -2918,7 +2920,7 @@ public RelBuilder hints(RelHint... hints) { * {@link org.apache.calcite.rel.hint.Hintable} */ public RelBuilder hints(Iterable hints) { - Objects.requireNonNull(hints); + requireNonNull(hints); final List relHintList = hints instanceof List ? (List) hints : Lists.newArrayList(hints); if (relHintList.isEmpty()) { @@ -2980,7 +2982,7 @@ private interface AggCallPlus extends AggCall { SqlAggFunction op(); /** Returns the alias. */ - String alias(); + @Nullable String alias(); /** Returns an {@link AggregateCall} that is approximately equivalent * to this {@code AggCall} and is good for certain things, such as deriving @@ -3017,7 +3019,7 @@ static class GroupKeyImpl implements GroupKey { GroupKeyImpl(ImmutableList nodes, @Nullable ImmutableList> nodeLists, @Nullable String alias) { - this.nodes = Objects.requireNonNull(nodes); + this.nodes = requireNonNull(nodes); this.nodeLists = nodeLists; this.alias = alias; } @@ -3056,7 +3058,7 @@ private class AggCallImpl implements AggCallPlus { boolean approximate, boolean ignoreNulls, @Nullable RexNode filter, @Nullable String alias, ImmutableList operands, ImmutableList orderKeys) { - this.aggFunction = Objects.requireNonNull(aggFunction); + this.aggFunction = requireNonNull(aggFunction); // If the aggregate function ignores DISTINCT, // make the DISTINCT flag FALSE. this.distinct = distinct @@ -3064,8 +3066,8 @@ private class AggCallImpl implements AggCallPlus { this.approximate = approximate; this.ignoreNulls = ignoreNulls; this.alias = alias; - this.operands = Objects.requireNonNull(operands); - this.orderKeys = Objects.requireNonNull(orderKeys); + this.operands = requireNonNull(operands); + this.orderKeys = requireNonNull(orderKeys); if (filter != null) { if (filter.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) { throw RESOURCE.filterMustBeBoolean().ex(); @@ -3103,13 +3105,16 @@ private class AggCallImpl implements AggCallPlus { return aggFunction; } - @Override public String alias() { + @Override public @Nullable String alias() { return alias; } @Override public AggregateCall aggregateCall() { return AggregateCall.create(aggFunction, distinct, approximate, - ignoreNulls, ImmutableList.of(), -1, null, null, alias); + ignoreNulls, ImmutableList.of(), -1, + requireNonNull(null, "CALCITE-4234: collation is null"), + requireNonNull(null, "CALCITE-4234: type is null"), + alias); } @Override public AggregateCall aggregateCall(Registrar registrar, @@ -3202,7 +3207,7 @@ private static class AggCallImpl2 implements AggCallPlus { private final AggregateCall aggregateCall; AggCallImpl2(AggregateCall aggregateCall) { - this.aggregateCall = Objects.requireNonNull(aggregateCall); + this.aggregateCall = requireNonNull(aggregateCall); } @Override public String toString() { @@ -3213,7 +3218,7 @@ private static class AggCallImpl2 implements AggCallPlus { return aggregateCall.getAggregation(); } - @Override public String alias() { + @Override public @Nullable String alias() { return aggregateCall.name; } diff --git a/core/src/main/java/org/apache/calcite/util/BarfingInvocationHandler.java b/core/src/main/java/org/apache/calcite/util/BarfingInvocationHandler.java index 636bc5f1c4ce..a02cf186c7f3 100644 --- a/core/src/main/java/org/apache/calcite/util/BarfingInvocationHandler.java +++ b/core/src/main/java/org/apache/calcite/util/BarfingInvocationHandler.java @@ -16,6 +16,8 @@ */ package org.apache.calcite.util; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.UndeclaredThrowableException; @@ -39,10 +41,10 @@ protected BarfingInvocationHandler() { //~ Methods ---------------------------------------------------------------- - @Override public Object invoke( + @Override public @Nullable Object invoke( Object proxy, Method method, - Object[] args) throws Throwable { + @Nullable Object[] args) throws Throwable { Class clazz = getClass(); Method matchingMethod; try { diff --git a/core/src/main/java/org/apache/calcite/util/BitSets.java b/core/src/main/java/org/apache/calcite/util/BitSets.java index c8c613bb276e..197ac8365e04 100644 --- a/core/src/main/java/org/apache/calcite/util/BitSets.java +++ b/core/src/main/java/org/apache/calcite/util/BitSets.java @@ -26,6 +26,8 @@ import java.util.SortedMap; import java.util.TreeMap; +import static java.util.Objects.requireNonNull; + /** * Utility functions for {@link BitSet}. */ @@ -325,7 +327,7 @@ private static class Closure { private SortedMap equivalence; private final NavigableMap closure = new TreeMap<>(); - @SuppressWarnings("JdkObsolete") + @SuppressWarnings({"JdkObsolete", "method.invocation.invalid"}) Closure(SortedMap equivalence) { this.equivalence = equivalence; final ImmutableIntList keys = @@ -341,7 +343,8 @@ private BitSet computeClosure(int pos) { if (o != null) { return o; } - BitSet b = equivalence.get(pos); + BitSet b = requireNonNull(equivalence.get(pos), + () -> "equivalence.get(pos) for " + pos); o = (BitSet) b.clone(); int i = b.nextSetBit(pos + 1); for (; i >= 0; i = b.nextSetBit(i + 1)) { diff --git a/core/src/main/java/org/apache/calcite/util/BlackholeMap.java b/core/src/main/java/org/apache/calcite/util/BlackholeMap.java index cd7b9e0d3332..f22c72a2d029 100644 --- a/core/src/main/java/org/apache/calcite/util/BlackholeMap.java +++ b/core/src/main/java/org/apache/calcite/util/BlackholeMap.java @@ -16,6 +16,8 @@ */ package org.apache.calcite.util; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Iterator; @@ -92,10 +94,12 @@ public static Set of() { private BlackholeMap() {} - @Override public V put(K key, V value) { + @SuppressWarnings("contracts.postcondition.not.satisfied") + @Override public @Nullable V put(K key, V value) { return null; } + @SuppressWarnings("override.return.invalid") @Override public Set> entrySet() { return BHSet.of(); } diff --git a/core/src/main/java/org/apache/calcite/util/CastingList.java b/core/src/main/java/org/apache/calcite/util/CastingList.java index 3e52ac9a95e9..5bdcb264d4c9 100644 --- a/core/src/main/java/org/apache/calcite/util/CastingList.java +++ b/core/src/main/java/org/apache/calcite/util/CastingList.java @@ -19,6 +19,8 @@ import java.util.AbstractList; import java.util.List; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Converts a list whose members are automatically down-cast to a given type. * @@ -48,7 +50,8 @@ protected CastingList(List list, Class clazz) { //~ Methods ---------------------------------------------------------------- @Override public E get(int index) { - return clazz.cast(list.get(index)); + Object o = list.get(index); + return clazz.cast(castNonNull(o)); } @Override public int size() { @@ -57,11 +60,12 @@ protected CastingList(List list, Class clazz) { @Override public E set(int index, E element) { final Object o = list.set(index, element); - return clazz.cast(o); + return clazz.cast(castNonNull(o)); } @Override public E remove(int index) { - return clazz.cast(list.remove(index)); + Object o = list.remove(index); + return clazz.cast(castNonNull(o)); } @Override public void add(int pos, E o) { 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 959c2be4a252..7f3ef18be956 100644 --- a/core/src/main/java/org/apache/calcite/util/ChunkList.java +++ b/core/src/main/java/org/apache/calcite/util/ChunkList.java @@ -27,6 +27,8 @@ import static org.apache.calcite.linq4j.Nullness.castNonNull; +import static java.util.Objects.requireNonNull; + /** * Implementation of list similar to {@link LinkedList}, but stores elements * in chunks of 32 elements. @@ -61,7 +63,8 @@ public ChunkList() { * Creates a ChunkList whose contents are a given Collection. */ public ChunkList(Collection collection) { - addAll(collection); + @SuppressWarnings({"method.invocation.invalid", "unused"}) + boolean ignore = addAll(collection); } /** @@ -87,8 +90,8 @@ boolean isValid(boolean fail) { assert !fail; return false; } - Object[] prev = null; - for (Object[] chunk = first; chunk != null; chunk = next(chunk)) { + E[] prev = null; + for (E[] chunk = first; chunk != null; chunk = next(chunk)) { if (prev(chunk) != prev) { assert !fail; return false; @@ -128,7 +131,7 @@ boolean isValid(boolean fail) { if (occupied == CHUNK_SIZE) { //noinspection unchecked chunk = (E[]) new Object[CHUNK_SIZE + HEADER_SIZE]; - setNext(last, chunk); + setNext(requireNonNull(last, "last"), chunk); setPrev(chunk, last); occupied = 0; last = chunk; @@ -169,12 +172,13 @@ private static void setNext(E[] chunk, E @Nullable [] next) { chunk[1] = (E) next; } - private static int occupied(Object[] chunk) { - return (Integer) chunk[2]; + private static int occupied(E[] chunk) { + return (Integer) requireNonNull(chunk[2], "chunk[2] (number of occupied entries)"); } - private static void setOccupied(Object[] chunk, int size) { - chunk[2] = INTEGERS[size]; + @SuppressWarnings("unchecked") + private static void setOccupied(E[] chunk, int size) { + chunk[2] = (E) INTEGERS[size]; } private static E element(E[] chunk, int index) { @@ -310,13 +314,13 @@ private E[] currentChunk() { if (prev == null) { chunk = first = next; setPrev(next, null); - end = occupied(chunk); + end = occupied(requireNonNull(chunk, "chunk")); } else { setNext(prev, next); setPrev(next, prev); chunk = prev; end = start; - start -= occupied(chunk); + start -= occupied(requireNonNull(chunk, "chunk")); } } lastRet = -1; @@ -327,24 +331,24 @@ private E[] currentChunk() { if (r < start) { // Element we wish to eliminate is the last element in the previous // block. - Object[] c = chunk; + E[] c = chunk; if (c == null) { c = last; } int o = occupied(castNonNull(c)); if (o == 1) { // Block is now empty; remove it - final Object[] prev = prev(c); + final E[] prev = prev(c); if (prev == null) { if (chunk == null) { first = last = null; } else { first = chunk; - setPrev(chunk, null); + setPrev(requireNonNull(chunk, "chunk"), null); } } else { - setNext(prev, chunk); - setPrev(chunk, prev); + setNext(requireNonNull(prev, "prev"), chunk); + setPrev(requireNonNull(chunk, "chunk"), prev); } } else { --o; @@ -383,7 +387,7 @@ private E[] currentChunk() { E[] newChunk = (E[]) new Object[CHUNK_SIZE + HEADER_SIZE]; if (first != null) { setNext(newChunk, first); - setPrev(first, newChunk); + setPrev(requireNonNull(first, "first"), newChunk); } first = newChunk; if (last == null) { @@ -398,7 +402,7 @@ private E[] currentChunk() { E[] newChunk = (E[]) new Object[CHUNK_SIZE + HEADER_SIZE]; final E[] next = ChunkList.next(chunk); setPrev(newChunk, chunk); - setNext(chunk, newChunk); + setNext(requireNonNull(chunk, "chunk"), newChunk); if (next == null) { last = newChunk; @@ -407,9 +411,9 @@ private E[] currentChunk() { setNext(newChunk, next); } - setOccupied(chunk, CHUNK_SIZE / 2); + setOccupied(requireNonNull(chunk, "chunk"), CHUNK_SIZE / 2); setOccupied(newChunk, CHUNK_SIZE / 2); - System.arraycopy(chunk, HEADER_SIZE + CHUNK_SIZE / 2, + System.arraycopy(requireNonNull(chunk, "chunk"), HEADER_SIZE + CHUNK_SIZE / 2, newChunk, HEADER_SIZE, CHUNK_SIZE / 2); Arrays.fill(chunk, HEADER_SIZE + CHUNK_SIZE / 2, HEADER_SIZE + CHUNK_SIZE, null); diff --git a/core/src/main/java/org/apache/calcite/util/CompositeMap.java b/core/src/main/java/org/apache/calcite/util/CompositeMap.java index 681f915f0269..b5f7acd0d7c9 100644 --- a/core/src/main/java/org/apache/calcite/util/CompositeMap.java +++ b/core/src/main/java/org/apache/calcite/util/CompositeMap.java @@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import org.checkerframework.checker.nullness.qual.KeyFor; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Collection; @@ -70,6 +71,7 @@ private static ImmutableList list(E e, E[] es) { return true; } + @SuppressWarnings("contracts.conditional.postcondition.not.satisfied") @Override public boolean containsKey(@Nullable Object key) { for (Map map : maps) { if (map.containsKey(key)) { @@ -103,7 +105,7 @@ private static ImmutableList list(E e, E[] es) { throw new UnsupportedOperationException(); } - @Override public V remove(Object key) { + @Override public V remove(@Nullable Object key) { // we are an unmodifiable view on the maps throw new UnsupportedOperationException(); } @@ -118,7 +120,8 @@ private static ImmutableList list(E e, E[] es) { throw new UnsupportedOperationException(); } - @Override public Set keySet() { + @SuppressWarnings("return.type.incompatible") + @Override public Set<@KeyFor("this") K> keySet() { final Set keys = new LinkedHashSet<>(); for (Map map : maps) { keys.addAll(map.keySet()); @@ -143,7 +146,8 @@ private Map combinedMap() { return combinedMap().values(); } - @Override public Set> entrySet() { + @SuppressWarnings("return.type.incompatible") + @Override public Set> entrySet() { return combinedMap().entrySet(); } } diff --git a/core/src/main/java/org/apache/calcite/util/ConversionUtil.java b/core/src/main/java/org/apache/calcite/util/ConversionUtil.java index 6646e237a9ac..72c418db3e87 100644 --- a/core/src/main/java/org/apache/calcite/util/ConversionUtil.java +++ b/core/src/main/java/org/apache/calcite/util/ConversionUtil.java @@ -16,6 +16,8 @@ */ package org.apache.calcite.util; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.nio.ByteOrder; import java.text.NumberFormat; import java.util.Locale; @@ -118,7 +120,7 @@ public static String toStringFromApprox(double d, boolean isFloat) { /** * Converts a string into a BOOLEAN. */ - public static Boolean toBoolean(String str) { + public static @Nullable Boolean toBoolean(@Nullable String str) { if (str == null) { return null; } diff --git a/core/src/main/java/org/apache/calcite/util/DelegatingInvocationHandler.java b/core/src/main/java/org/apache/calcite/util/DelegatingInvocationHandler.java index 82fe4982c698..a2375d504b0b 100644 --- a/core/src/main/java/org/apache/calcite/util/DelegatingInvocationHandler.java +++ b/core/src/main/java/org/apache/calcite/util/DelegatingInvocationHandler.java @@ -56,7 +56,7 @@ public abstract class DelegatingInvocationHandler implements InvocationHandler { @Override public @Nullable Object invoke( Object proxy, Method method, - Object[] args) throws Throwable { + @Nullable Object[] args) throws Throwable { Class clazz = getClass(); Method matchingMethod; try { @@ -78,7 +78,7 @@ public abstract class DelegatingInvocationHandler implements InvocationHandler { args); } } catch (InvocationTargetException e) { - throw e.getTargetException(); + throw Util.first(e.getCause(), e); } } diff --git a/core/src/main/java/org/apache/calcite/util/EquivalenceSet.java b/core/src/main/java/org/apache/calcite/util/EquivalenceSet.java index 8a7f73319c19..2b43f94aacfe 100644 --- a/core/src/main/java/org/apache/calcite/util/EquivalenceSet.java +++ b/core/src/main/java/org/apache/calcite/util/EquivalenceSet.java @@ -71,14 +71,14 @@ public E add(E e) { public E equiv(E e, E f) { final E eParent = add(e); if (!eParent.equals(e)) { - assert parents.get(eParent).equals(eParent); + assert Objects.equals(parents.get(eParent), eParent); final E root = equiv(eParent, f); parents.put(e, root); return root; } final E fParent = add(f); if (!fParent.equals(f)) { - assert parents.get(fParent).equals(fParent); + assert Objects.equals(parents.get(fParent), fParent); final E root = equiv(e, fParent); parents.put(f, root); return root; diff --git a/core/src/main/java/org/apache/calcite/util/Filterator.java b/core/src/main/java/org/apache/calcite/util/Filterator.java index c2a4fdf4af87..c605a0b851d1 100644 --- a/core/src/main/java/org/apache/calcite/util/Filterator.java +++ b/core/src/main/java/org/apache/calcite/util/Filterator.java @@ -16,9 +16,13 @@ */ package org.apache.calcite.util; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Iterator; import java.util.NoSuchElementException; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Filtered iterator class: an iterator that includes only elements that are * instanceof a specified class. @@ -30,12 +34,12 @@ * * @param Element type */ -public class Filterator implements Iterator { +public class Filterator implements Iterator { //~ Instance fields -------------------------------------------------------- Class includeFilter; - Iterator iterator; - E lookAhead; + Iterator iterator; + @Nullable E lookAhead; boolean ready; //~ Constructors ----------------------------------------------------------- @@ -68,7 +72,7 @@ public Filterator(Iterator iterator, Class includeFilter) { if (ready) { E o = lookAhead; ready = false; - return o; + return castNonNull(o); } while (iterator.hasNext()) { diff --git a/core/src/main/java/org/apache/calcite/util/ImmutableBeans.java b/core/src/main/java/org/apache/calcite/util/ImmutableBeans.java index f627a9af3bd2..9c6511ab501c 100644 --- a/core/src/main/java/org/apache/calcite/util/ImmutableBeans.java +++ b/core/src/main/java/org/apache/calcite/util/ImmutableBeans.java @@ -26,6 +26,8 @@ import com.google.common.collect.ImmutableSortedMap; import com.google.common.util.concurrent.UncheckedExecutionException; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -47,6 +49,8 @@ import java.util.TreeMap; import java.util.concurrent.ExecutionException; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** Utilities for creating immutable beans. */ public class ImmutableBeans { /** Cache of method handlers of each known class, because building a set of @@ -68,19 +72,19 @@ public class ImmutableBeans { private ImmutableBeans() {} /** Creates an immutable bean that implements a given interface. */ - public static T create(Class beanClass) { + public static T create(Class beanClass) { return create_(beanClass, ImmutableMap.of()); } /** Creates a bean of a given class whose contents are the same as this bean. * *

You typically use this to downcast a bean to a sub-class. */ - public static T copy(Class beanClass, Object o) { + public static T copy(Class beanClass, Object o) { final BeanImpl bean = (BeanImpl) Proxy.getInvocationHandler(o); return create_(beanClass, bean.map); } - private static T create_(Class beanClass, + private static T create_(Class beanClass, ImmutableMap valueMap) { if (!beanClass.isInterface()) { throw new IllegalArgumentException("must be interface"); @@ -98,7 +102,7 @@ private static T create_(Class beanClass, } } - private static Def makeDef(Class beanClass) { + private static Def makeDef(Class beanClass) { final ImmutableSortedMap.Builder propertyNameBuilder = ImmutableSortedMap.naturalOrder(); final ImmutableMap.Builder> handlers = @@ -347,7 +351,7 @@ private static boolean hasAnnotation(AnnotatedElement element, String className) return false; } - private static Object getDefault(Method method) { + private static @Nullable Object getDefault(Method method) { Object defaultValue = null; final IntDefault intDefault = method.getAnnotation(IntDefault.class); if (intDefault != null) { @@ -371,7 +375,7 @@ private static Object getDefault(Method method) { return defaultValue; } - private static Object convertDefault(Object defaultValue, String propertyName, + private static @Nullable Object convertDefault(@Nullable Object defaultValue, String propertyName, Class propertyType) { if (propertyType.equals(SqlConformance.class)) { // Workaround for SqlConformance because it is actually not a Enum. @@ -380,7 +384,8 @@ private static Object convertDefault(Object defaultValue, String propertyName, if (defaultValue == null || !propertyType.isEnum()) { return defaultValue; } - for (Object enumConstant : propertyType.getEnumConstants()) { + // checkerframework does not infer "isEnum" here, so castNonNull + for (Object enumConstant : castNonNull(propertyType.getEnumConstants())) { if (((Enum) enumConstant).name().equals(defaultValue)) { return enumConstant; } @@ -407,8 +412,8 @@ private enum Mode { /** Handler for a particular method call; called with "this" and arguments. * * @param Bean type */ - private interface Handler { - Object apply(BeanImpl bean, Object[] args); + private interface Handler { + @Nullable Object apply(BeanImpl bean, @Nullable Object[] args); } /** Property of a bean. Apply this annotation to the "get" method. */ @@ -458,7 +463,7 @@ private interface Handler { * so that it can retrieve calls from a reflective proxy. * * @param Bean type */ - private static class BeanImpl implements InvocationHandler { + private static class BeanImpl implements InvocationHandler { private final Def def; private final ImmutableMap map; @@ -467,7 +472,7 @@ private static class BeanImpl implements InvocationHandler { this.map = Objects.requireNonNull(map); } - @Override public Object invoke(Object proxy, Method method, Object[] args) { + @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) { final Handler handler = def.handlers.get(method); if (handler == null) { throw new IllegalArgumentException("no handler for method " + method); @@ -492,7 +497,7 @@ T asBean() { /** Definition of a bean. Consists of its class and handlers. * * @param Class of bean */ - private static class Def { + private static class Def { private final Class beanClass; private final ImmutableMap> handlers; 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 3157bf3a4b29..a896263e4c80 100644 --- a/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java +++ b/core/src/main/java/org/apache/calcite/util/ImmutableBitSet.java @@ -1113,18 +1113,25 @@ public int cardinality() { /** Merges another builder. Does not modify the other builder. */ public Builder combine(Builder builder) { - if (words.length < builder.words.length) { + if (words == null) { + throw new IllegalArgumentException("can only use builder once"); + } + long[] otherWords = builder.words; + if (otherWords == null) { + throw new IllegalArgumentException("Given builder is empty"); + } + if (this.words.length < otherWords.length) { // Right has more bits. Copy the right and OR in the words of the // previous left. - final long[] newWords = builder.words.clone(); - for (int i = 0; i < words.length; i++) { - newWords[i] |= words[i]; + final long[] newWords = otherWords.clone(); + for (int i = 0; i < this.words.length; i++) { + newWords[i] |= this.words[i]; } - words = newWords; + this.words = newWords; } else { // Left has same or more bits. OR in the words of the right. - for (int i = 0; i < builder.words.length; i++) { - words[i] |= builder.words[i]; + for (int i = 0; i < otherWords.length; i++) { + this.words[i] |= otherWords[i]; } } return this; 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 e6fdb3eeebba..7dc305b5f7ed 100644 --- a/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java +++ b/core/src/main/java/org/apache/calcite/util/ImmutableIntList.java @@ -208,7 +208,7 @@ public int getInt(int index) { }; } - @Override public int indexOf(Object o) { + @Override public int indexOf(@Nullable Object o) { if (o instanceof Integer) { return indexOf((int) (Integer) o); } @@ -224,7 +224,7 @@ public int indexOf(int seek) { return -1; } - @Override public int lastIndexOf(Object o) { + @Override public int lastIndexOf(@Nullable Object o) { if (o instanceof Integer) { return lastIndexOf((int) (Integer) o); } diff --git a/core/src/main/java/org/apache/calcite/util/ImmutableNullableMap.java b/core/src/main/java/org/apache/calcite/util/ImmutableNullableMap.java index 5bca457ec215..94f731e7ba25 100644 --- a/core/src/main/java/org/apache/calcite/util/ImmutableNullableMap.java +++ b/core/src/main/java/org/apache/calcite/util/ImmutableNullableMap.java @@ -21,6 +21,7 @@ import java.util.AbstractMap; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.SortedMap; @@ -60,7 +61,12 @@ public static Map copyOf(Map map) { if (map instanceof SortedMap) { final SortedMap sortedMap = (SortedMap) map; try { - return ImmutableSortedMap.copyOf(sortedMap, sortedMap.comparator()); + Comparator comparator = sortedMap.comparator(); + if (comparator == null) { + return ImmutableSortedMap.copyOf(sortedMap); + } else { + return ImmutableSortedMap.copyOf(sortedMap, comparator); + } } catch (NullPointerException e) { // Make an effectively immutable map by creating a mutable copy // and wrapping it to prevent modification. Unfortunately, if we see @@ -98,7 +104,12 @@ public static Map copyOf( } final SortedMap sortedMap = (SortedMap) map; try { - return ImmutableSortedMap.copyOf(sortedMap, sortedMap.comparator()); + Comparator comparator = sortedMap.comparator(); + if (comparator == null) { + return ImmutableSortedMap.copyOf(sortedMap); + } else { + return ImmutableSortedMap.copyOf(sortedMap, comparator); + } } catch (NullPointerException e) { // Make an effectively immutable map by creating a mutable copy // and wrapping it to prevent modification. Unfortunately, if we see diff --git a/core/src/main/java/org/apache/calcite/util/ImmutableNullableSet.java b/core/src/main/java/org/apache/calcite/util/ImmutableNullableSet.java index ea1700dbe0ce..434c5ddb5680 100644 --- a/core/src/main/java/org/apache/calcite/util/ImmutableNullableSet.java +++ b/core/src/main/java/org/apache/calcite/util/ImmutableNullableSet.java @@ -23,6 +23,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.AbstractSet; @@ -35,6 +36,8 @@ import java.util.Objects; import java.util.Set; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * An immutable set that may contain null values. * @@ -58,8 +61,8 @@ private ImmutableNullableSet(ImmutableSet elements) { } @Override public Iterator iterator() { - return Iterators.transform(elements.iterator(), e -> - e == NullSentinel.INSTANCE ? null : (E) e); + return Util.transform(elements.iterator(), e -> + e == NullSentinel.INSTANCE ? castNonNull(null) : (E) e); } @Override public int size() { @@ -137,7 +140,7 @@ private static Set copyOf(E[] elements, boolean needCopy) { return ImmutableSet.copyOf(elements); } - final Object[] objects = + final @Nullable Object[] objects = needCopy ? Arrays.copyOf(elements, elements.length, Object[].class) : elements; for (int i = 0; i < objects.length; i++) { @@ -145,7 +148,9 @@ private static Set copyOf(E[] elements, boolean needCopy) { objects[i] = NullSentinel.INSTANCE; } } - return new ImmutableNullableSet(ImmutableSet.copyOf(objects)); + @SuppressWarnings({"nullness", "NullableProblems"}) + @NonNull Object[] nonNullObjects = objects; + return new ImmutableNullableSet(ImmutableSet.copyOf(nonNullObjects)); } private static boolean containsNull(E[] elements) { 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 9700ebb78729..26cffeaa4346 100644 --- a/core/src/main/java/org/apache/calcite/util/Pair.java +++ b/core/src/main/java/org/apache/calcite/util/Pair.java @@ -17,7 +17,6 @@ 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; @@ -269,11 +268,11 @@ public static List> zipMutable( * @param Right type */ public static void forEach( - final Iterable ks, - final Iterable vs, - BiConsumer<@PolyNull K, @PolyNull V> consumer) { - final Iterator leftIterator = ks.iterator(); - final Iterator rightIterator = vs.iterator(); + final Iterable ks, + final Iterable vs, + BiConsumer 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/PartiallyOrderedSet.java b/core/src/main/java/org/apache/calcite/util/PartiallyOrderedSet.java index 13f12f550c45..eb85c317064b 100644 --- a/core/src/main/java/org/apache/calcite/util/PartiallyOrderedSet.java +++ b/core/src/main/java/org/apache/calcite/util/PartiallyOrderedSet.java @@ -33,10 +33,13 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.function.Function; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + +import static java.util.Objects.requireNonNull; + /** * Partially-ordered set. @@ -481,14 +484,14 @@ public boolean isValid(boolean fail) { } } if (lt12 && !lt21) { - if (!nodeAncestors.get(node1).contains(node2.e)) { + if (!get(nodeAncestors, node1, "nodeAncestors").contains(node2.e)) { assert !fail : node1.e + " is less than " + node2.e + " but " + node2.e + " is not in the ancestor set of " + node1.e; return false; } - if (!nodeDescendants.get(node2).contains(node1.e)) { + if (!get(nodeDescendants, node2, "nodeDescendants").contains(node1.e)) { assert !fail : node1.e + " is less than " + node2.e + " but " + node1.e + " is not in the descendant set of " @@ -497,14 +500,14 @@ public boolean isValid(boolean fail) { } } if (lt21 && !lt12) { - if (!nodeAncestors.get(node2).contains(node1.e)) { + if (!get(nodeAncestors, node2, "nodeAncestors").contains(node1.e)) { assert !fail : node2.e + " is less than " + node1.e + " but " + node1.e + " is not in the ancestor set of " + node2.e; return false; } - if (!nodeDescendants.get(node1).contains(node2.e)) { + if (!get(nodeDescendants, node1, "nodeDescendants").contains(node2.e)) { assert !fail : node2.e + " is less than " + node1.e + " but " + node2.e + " is not in the descendant set of " @@ -517,6 +520,11 @@ public boolean isValid(boolean fail) { return true; } + private static Set get(Map, Set> map, Node node, String label) { + return requireNonNull(map.get(node), + () -> label + " for node " + node); + } + private void distanceRecurse( Map distanceToRoot, Node node, @@ -557,9 +565,11 @@ public void out(StringBuilder buf) { buf.append(children); buf.append("\n"); - for (E child : children) { - if (seen.add(child)) { - unseen.add(child); + if (children != null) { + for (E child : children) { + if (seen.add(child)) { + unseen.add(child); + } } } } @@ -578,7 +588,7 @@ public void out(StringBuilder buf) { * @return List of values in this set that are directly less than the given * value */ - public List getChildren(E e) { + public @Nullable List getChildren(E e) { return getChildren(e, false); } @@ -596,7 +606,7 @@ public List getChildren(E e) { * @return List of values in this set that are directly less than the given * value */ - public List getChildren(E e, boolean hypothetical) { + public @Nullable List getChildren(E e, boolean hypothetical) { final Node node = map.get(e); if (node == null) { if (hypothetical) { @@ -621,7 +631,7 @@ public List getChildren(E e, boolean hypothetical) { * @return List of values in this set that are directly greater than the * given value */ - public List getParents(E e) { + public @Nullable List getParents(E e) { return getParents(e, false); } @@ -639,7 +649,7 @@ public List getParents(E e) { * @return List of values in this set that are directly greater than the * given value */ - public List getParents(E e, boolean hypothetical) { + public @Nullable List getParents(E e, boolean hypothetical) { final Node node = map.get(e); if (node == null) { if (hypothetical) { @@ -660,7 +670,7 @@ public List getParents(E e, boolean hypothetical) { private void closure(Function> generator, E e, ImmutableList.Builder list, Set set) { - for (E p : Objects.requireNonNull(generator.apply(e))) { + for (E p : requireNonNull(generator.apply(e))) { if (set.add(e)) { if (map.containsKey(p)) { list.add(p); @@ -810,7 +820,7 @@ private static class Node { } @Override public String toString() { - return e.toString(); + return String.valueOf(e); } } @@ -824,7 +834,7 @@ private static class TopBottomNode extends Node { private final String description; TopBottomNode(boolean top) { - super(null); + super(castNonNull(null)); this.description = top ? "top" : "bottom"; } diff --git a/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java b/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java index 4ba7edc3e5ca..dd8f2379a2f6 100644 --- a/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java +++ b/core/src/main/java/org/apache/calcite/util/RelToSqlConverterUtil.java @@ -28,6 +28,8 @@ import static org.apache.calcite.sql.fun.SqlLibraryOperators.REGEXP_REPLACE; +import static java.util.Objects.requireNonNull; + /** * Utilities used by multiple dialect for RelToSql conversion. */ @@ -43,7 +45,9 @@ public static void unparseHiveTrim( int leftPrec, int rightPrec) { final SqlLiteral valueToTrim = call.operand(1); - if (valueToTrim.toValue().matches("\\s+")) { + String value = requireNonNull(valueToTrim.toValue(), + () -> "call.operand(1).toValue() for call " + call); + if (value.matches("\\s+")) { unparseTrimWithSpace(writer, call, leftPrec, rightPrec); } else { // SELECT TRIM(both 'A' from "ABC") -> SELECT REGEXP_REPLACE("ABC", '^(A)*', '') @@ -98,7 +102,8 @@ private static void unparseTrimWithSpace( * @return the regex pattern of the character to be trimmed */ public static SqlCharStringLiteral createRegexPatternLiteral(SqlNode call, SqlLiteral trimFlag) { - final String regexPattern = ((SqlCharStringLiteral) call).toValue(); + final String regexPattern = requireNonNull(((SqlCharStringLiteral) call).toValue(), + () -> "null value for SqlNode " + call); String escaped = escapeSpecialChar(regexPattern); final StringBuilder builder = new StringBuilder(); switch (trimFlag.getValueAs(SqlTrimFunction.Flag.class)) { diff --git a/core/src/main/java/org/apache/calcite/util/SerializableCharset.java b/core/src/main/java/org/apache/calcite/util/SerializableCharset.java index ed042abf2027..8138af8e23c9 100644 --- a/core/src/main/java/org/apache/calcite/util/SerializableCharset.java +++ b/core/src/main/java/org/apache/calcite/util/SerializableCharset.java @@ -16,12 +16,16 @@ */ package org.apache.calcite.util; +import org.checkerframework.checker.nullness.qual.PolyNull; + import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.nio.charset.Charset; +import static java.util.Objects.requireNonNull; + /** * Serializable wrapper around a {@link Charset}. * @@ -67,7 +71,8 @@ private void writeObject(ObjectOutputStream out) throws IOException { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { charsetName = (String) in.readObject(); - charset = Charset.availableCharsets().get(this.charsetName); + charset = requireNonNull(Charset.availableCharsets().get(this.charsetName), + () -> "charset is not found: " + charsetName); } /** @@ -86,7 +91,7 @@ public Charset getCharset() { * @param charset Character set to wrap, or null * @return Wrapped charset */ - public static SerializableCharset forCharset(Charset charset) { + public static @PolyNull SerializableCharset forCharset(@PolyNull Charset charset) { if (charset == null) { return null; } diff --git a/core/src/main/java/org/apache/calcite/util/SimpleNamespaceContext.java b/core/src/main/java/org/apache/calcite/util/SimpleNamespaceContext.java index 068034e024f4..68bab8f134f5 100644 --- a/core/src/main/java/org/apache/calcite/util/SimpleNamespaceContext.java +++ b/core/src/main/java/org/apache/calcite/util/SimpleNamespaceContext.java @@ -36,6 +36,7 @@ public class SimpleNamespaceContext implements NamespaceContext { private final Map prefixToNamespaceUri = new HashMap<>(); private final Map> namespaceUriToPrefixes = new HashMap<>(); + @SuppressWarnings({"method.invocation.invalid", "methodref.receiver.bound.invalid"}) public SimpleNamespaceContext(Map bindings) { bindNamespaceUri(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI); bindNamespaceUri(XMLConstants.XMLNS_ATTRIBUTE, XMLConstants.XMLNS_ATTRIBUTE_NS_URI); diff --git a/core/src/main/java/org/apache/calcite/util/Template.java b/core/src/main/java/org/apache/calcite/util/Template.java index a0e89b2733c1..11047261af4f 100644 --- a/core/src/main/java/org/apache/calcite/util/Template.java +++ b/core/src/main/java/org/apache/calcite/util/Template.java @@ -18,6 +18,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; @@ -218,7 +220,7 @@ private static void makeFormat( * object */ public String format(Map argMap) { - Object[] args = new Object[parameterNames.size()]; + @Nullable Object[] args = new Object[parameterNames.size()]; for (int i = 0; i < parameterNames.size(); i++) { args[i] = getArg(argMap, i); } @@ -232,7 +234,7 @@ public String format(Map argMap) { * @param ordinal Ordinal of argument * @return Value of argument */ - private Object getArg(Map argMap, int ordinal) { + private @Nullable Object getArg(Map argMap, int ordinal) { // First get by name. String parameterName = parameterNames.get(ordinal); Object arg = argMap.get(parameterName); diff --git a/core/src/main/java/org/apache/calcite/util/Util.java b/core/src/main/java/org/apache/calcite/util/Util.java index f6cbf0ba210f..31ac0862433a 100644 --- a/core/src/main/java/org/apache/calcite/util/Util.java +++ b/core/src/main/java/org/apache/calcite/util/Util.java @@ -111,6 +111,8 @@ import java.util.regex.Pattern; import java.util.stream.Collector; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** * Miscellaneous utility functions. @@ -1740,7 +1742,7 @@ public static List cast(List list, Class clazz) { public static Iterator cast( final Iterator iter, final Class clazz) { - return transform(iter, clazz::cast); + return transform(iter, x -> clazz.cast(castNonNull(x))); } /** @@ -1940,7 +1942,7 @@ public static > Map enumConstants( * @param Enum class type * @return Enum constant or null */ - public static synchronized > T enumVal( + public static synchronized > @Nullable T enumVal( Class clazz, String name) { return clazz.cast(ENUM_CONSTANTS.getUnchecked(clazz).get(name)); @@ -1956,7 +1958,7 @@ public static synchronized > T enumVal( * @return Enum constant, never null */ public static synchronized > T enumVal(T default_, - String name) { + @Nullable String name) { final Class clazz = default_.getDeclaringClass(); final T t = clazz.cast(ENUM_CONSTANTS.getUnchecked(clazz).get(name)); if (t == null) { @@ -2012,7 +2014,7 @@ public static List> pairs(final List list) { * *

Equivalent to the Elvis operator ({@code ?:}) of languages such as * Groovy or PHP. */ - public static @PolyNull T first(T v0, T2 v1) { + public static @PolyNull T first(@Nullable T v0, @PolyNull T v1) { return v0 != null ? v0 : v1; } @@ -2603,7 +2605,7 @@ public static List transform(List list, /** Transforms a iterator, applying a function to each element. */ @CheckReturnValue - @API(since = "1.26", status = API.Status.EXPERIMENTAL) + @API(since = "1.27", status = API.Status.EXPERIMENTAL) public static Iterable transform(Iterable iterable, java.util.function.Function function) { // FluentIterable provides toString @@ -2616,7 +2618,7 @@ public static Iterable transform(Iterable iterable, /** Transforms an iterator. */ @CheckReturnValue - @API(since = "1.26", status = API.Status.EXPERIMENTAL) + @API(since = "1.27", status = API.Status.EXPERIMENTAL) public static Iterator transform(Iterator iterator, java.util.function.Function function) { return new TransformingIterator<>(iterator, function); @@ -2624,7 +2626,7 @@ public static Iterator transform(Iterator iterator, /** Filters an iterable. */ @CheckReturnValue - @API(since = "1.26", status = API.Status.EXPERIMENTAL) + @API(since = "1.27", status = API.Status.EXPERIMENTAL) public static Iterable filter(Iterable iterable, Predicate predicate) { // FluentIterable provides toString @@ -2637,7 +2639,7 @@ public static Iterable filter(Iterable iterable, /** Filters an iterator. */ @CheckReturnValue - @API(since = "1.26", status = API.Status.EXPERIMENTAL) + @API(since = "1.27", status = API.Status.EXPERIMENTAL) public static Iterator filter(Iterator iterator, Predicate predicate) { return new FilteringIterator<>(iterator, predicate); diff --git a/core/src/main/java/org/apache/calcite/util/XmlOutput.java b/core/src/main/java/org/apache/calcite/util/XmlOutput.java index 5bdcc5b5f957..e20ea6a19624 100644 --- a/core/src/main/java/org/apache/calcite/util/XmlOutput.java +++ b/core/src/main/java/org/apache/calcite/util/XmlOutput.java @@ -26,6 +26,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Deque; +import java.util.List; + +import static java.util.Objects.requireNonNull; /** * Streaming XML output. @@ -543,7 +546,7 @@ private static boolean stringHasXMLSpecials(String input) { * use one of the global mappings pre-defined here.

*/ static class StringEscaper implements Cloneable { - private @Nullable ArrayList<@Nullable String> translationVector; + private @Nullable List<@Nullable String> translationVector; private String @Nullable [] translationTable; public static final StringEscaper XML_ESCAPER; @@ -562,6 +565,8 @@ static class StringEscaper implements Cloneable { */ public void defineEscape(char from, String to) { int i = (int) from; + List<@Nullable String> translationVector = requireNonNull(this.translationVector, + "translationVector"); if (i >= translationVector.size()) { // Extend list by adding the requisite number of nulls. final int count = i + 1 - translationVector.size(); @@ -574,9 +579,10 @@ public void defineEscape(char from, String to) { * Call this before attempting to escape strings; after this, * defineEscape may not be called again. */ + @SuppressWarnings("assignment.type.incompatible") public void makeImmutable() { translationTable = - translationVector.toArray(new String[0]); + requireNonNull(translationVector, "translationVector").toArray(new String[0]); translationVector = null; } @@ -592,7 +598,7 @@ public String escapeString(String s) { // codes >= 128 (e.g. Euro sign) are always escaped if (c > 127) { escape = "&#" + Integer.toString(c) + ";"; - } else if (c >= translationTable.length) { + } else if (c >= requireNonNull(translationTable, "translationTable").length) { escape = null; } else { escape = translationTable[c]; @@ -635,7 +641,8 @@ public String escapeString(String s) { public StringEscaper getMutableClone() { StringEscaper clone = clone(); if (clone.translationVector == null) { - clone.translationVector = Lists.newArrayList(clone.translationTable); + clone.translationVector = Lists.newArrayList( + requireNonNull(clone.translationTable, "clone.translationTable")); clone.translationTable = null; } return clone; diff --git a/core/src/main/java/org/apache/calcite/util/graph/Graphs.java b/core/src/main/java/org/apache/calcite/util/graph/Graphs.java index 3e2230d23c07..e9727e3f96ad 100644 --- a/core/src/main/java/org/apache/calcite/util/graph/Graphs.java +++ b/core/src/main/java/org/apache/calcite/util/graph/Graphs.java @@ -29,6 +29,8 @@ import java.util.Map; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** * Miscellaneous graph utilities. */ @@ -75,7 +77,8 @@ public static FrozenGraph makeImmutable( if (edge.target.equals(edge2.left)) { final Pair key = Pair.of(graph1.source(edge), edge2.right); int[] bestDistance = shortestDistances.get(key); - int[] arc2Distance = shortestDistances.get(edge2); + int[] arc2Distance = requireNonNull(shortestDistances.get(edge2), + () -> "shortestDistances.get(edge2) for " + edge2); if ((bestDistance == null) || (bestDistance[0] > (arc2Distance[0] + 1))) { shortestDistances.put(key, new int[] {arc2Distance[0] + 1}); @@ -97,7 +100,7 @@ public static FrozenGraph makeImmutable( * @param Vertex type * @param Edge type */ - public static class FrozenGraph { + public static class FrozenGraph { private final DefaultDirectedGraph graph; private final Map, int[]> shortestDistances; diff --git a/core/src/main/java/org/apache/calcite/util/graph/TopologicalOrderIterator.java b/core/src/main/java/org/apache/calcite/util/graph/TopologicalOrderIterator.java index 2ee16df2529c..ada55196790a 100644 --- a/core/src/main/java/org/apache/calcite/util/graph/TopologicalOrderIterator.java +++ b/core/src/main/java/org/apache/calcite/util/graph/TopologicalOrderIterator.java @@ -16,14 +16,18 @@ */ package org.apache.calcite.util.graph; +import org.checkerframework.checker.initialization.qual.UnderInitialization; +import org.checkerframework.checker.nullness.qual.RequiresNonNull; + import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; +import static java.util.Objects.requireNonNull; + /** * Iterates over the edges of a graph in topological order. @@ -47,7 +51,10 @@ public static Iterable of( return () -> new TopologicalOrderIterator<>(graph); } - private void populate(Map countMap, List empties) { + @RequiresNonNull("graph") + private void populate( + @UnderInitialization TopologicalOrderIterator this, + Map countMap, List empties) { for (V v : graph.vertexMap.keySet()) { countMap.put(v, new int[] {0}); } @@ -55,7 +62,9 @@ private void populate(Map countMap, List empties) { : graph.vertexMap.values()) { for (E edge : info.outEdges) { //noinspection SuspiciousMethodCalls - final int[] ints = countMap.get(edge.target); + final int[] ints = requireNonNull( + countMap.get(edge.target), + () -> "no value for " + edge.target); ++ints[0]; } } @@ -73,10 +82,13 @@ private void populate(Map countMap, List empties) { @Override public V next() { V v = empties.remove(0); - for (E o : graph.vertexMap.get(v).outEdges) { + DefaultDirectedGraph.VertexInfo vertexInfo = requireNonNull( + graph.vertexMap.get(v), + () -> "no vertex " + v); + for (E o : vertexInfo.outEdges) { //noinspection unchecked final V target = (V) o.target; - int[] ints = Objects.requireNonNull( + int[] ints = requireNonNull( countMap.get(target), () -> "no counts found for target " + target); if (--ints[0] == 0) { @@ -95,6 +107,7 @@ Set findCycles() { while (hasNext()) { next(); } - return countMap.keySet(); + //noinspection RedundantCast + return (Set) countMap.keySet(); } } diff --git a/core/src/main/java/org/apache/calcite/util/javac/JaninoCompiler.java b/core/src/main/java/org/apache/calcite/util/javac/JaninoCompiler.java index 47508616423f..001a0bf16117 100644 --- a/core/src/main/java/org/apache/calcite/util/javac/JaninoCompiler.java +++ b/core/src/main/java/org/apache/calcite/util/javac/JaninoCompiler.java @@ -18,6 +18,7 @@ import org.apache.calcite.config.CalciteSystemProperty; +import org.checkerframework.checker.nullness.qual.Nullable; import org.codehaus.janino.JavaSourceClassLoader; import org.codehaus.janino.util.ClassFile; import org.codehaus.janino.util.resource.MapResourceFinder; @@ -30,6 +31,8 @@ import java.util.HashMap; import java.util.Map; +import static java.util.Objects.requireNonNull; + /** * JaninoCompiler implements the {@link JavaCompiler} interface by * calling Janino. @@ -40,7 +43,7 @@ public class JaninoCompiler implements JavaCompiler { public JaninoCompilerArgs args = new JaninoCompilerArgs(); // REVIEW jvs 28-June-2004: pool this instance? Is it thread-safe? - private AccountingClassLoader classLoader; + private @Nullable AccountingClassLoader classLoader; //~ Constructors ----------------------------------------------------------- @@ -57,9 +60,9 @@ public JaninoCompiler() { // class and its callers to specify all code to compile in one // go, we could probably just use a single AccountingClassLoader. - assert args.destdir != null; - assert args.fullClassName != null; - assert args.source != null; + String destdir = requireNonNull(args.destdir, "args.destdir"); + String fullClassName = requireNonNull(args.fullClassName, "args.fullClassName"); + String source = requireNonNull(args.source, "args.source"); ClassLoader parentClassLoader = args.getClassLoader(); if (classLoader != null) { @@ -68,24 +71,24 @@ public JaninoCompiler() { Map sourceMap = new HashMap<>(); sourceMap.put( - ClassFile.getSourceResourceName(args.fullClassName), - args.source.getBytes(StandardCharsets.UTF_8)); + ClassFile.getSourceResourceName(fullClassName), + source.getBytes(StandardCharsets.UTF_8)); MapResourceFinder sourceFinder = new MapResourceFinder(sourceMap); - classLoader = + AccountingClassLoader classLoader = this.classLoader = new AccountingClassLoader( parentClassLoader, sourceFinder, null, - args.destdir == null ? null : new File(args.destdir)); + destdir == null ? null : new File(destdir)); if (CalciteSystemProperty.DEBUG.value()) { // Add line numbers to the generated janino class classLoader.setDebuggingInfo(true, true, true); } try { - classLoader.loadClass(args.fullClassName); + classLoader.loadClass(fullClassName); } catch (ClassNotFoundException ex) { - throw new RuntimeException("while compiling " + args.fullClassName, ex); + throw new RuntimeException("while compiling " + fullClassName, ex); } } @@ -96,12 +99,16 @@ public JaninoCompiler() { // implement JavaCompiler @Override public ClassLoader getClassLoader() { - return classLoader; + return getAccountingClassLoader(); + } + + private AccountingClassLoader getAccountingClassLoader() { + return requireNonNull(classLoader, "classLoader is null. Need to call #compile()"); } // implement JavaCompiler @Override public int getTotalByteCodeSize() { - return classLoader.getTotalByteCodeSize(); + return getAccountingClassLoader().getTotalByteCodeSize(); } //~ Inner Classes ---------------------------------------------------------- @@ -110,9 +117,9 @@ public JaninoCompiler() { * Arguments to an invocation of the Janino compiler. */ public static class JaninoCompilerArgs extends JavaCompilerArgs { - String destdir; - String fullClassName; - String source; + @Nullable String destdir; + @Nullable String fullClassName; + @Nullable String source; public JaninoCompilerArgs() { } @@ -141,14 +148,14 @@ public JaninoCompilerArgs() { * bytecode length of the classes it has compiled. */ private static class AccountingClassLoader extends JavaSourceClassLoader { - private final File destDir; + private final @Nullable File destDir; private int nBytes; AccountingClassLoader( ClassLoader parentClassLoader, ResourceFinder sourceFinder, - String optionalCharacterEncoding, - File destDir) { + @Nullable String optionalCharacterEncoding, + @Nullable File destDir) { super( parentClassLoader, sourceFinder, @@ -160,7 +167,7 @@ int getTotalByteCodeSize() { return nBytes; } - @Override public Map generateBytecodes(String name) + @Override public @Nullable Map generateBytecodes(String name) throws ClassNotFoundException { final Map map = super.generateBytecodes(name); if (map == null) { diff --git a/core/src/main/java/org/apache/calcite/util/javac/JavaCompilerArgs.java b/core/src/main/java/org/apache/calcite/util/javac/JavaCompilerArgs.java index 0c3287dc0155..6b93d7310f9f 100644 --- a/core/src/main/java/org/apache/calcite/util/javac/JavaCompilerArgs.java +++ b/core/src/main/java/org/apache/calcite/util/javac/JavaCompilerArgs.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.StringTokenizer; +import static java.util.Objects.requireNonNull; + /** * A JavaCompilerArgs holds the arguments for a * {@link JavaCompiler}. @@ -40,7 +42,8 @@ public class JavaCompilerArgs { //~ Constructors ----------------------------------------------------------- public JavaCompilerArgs() { - classLoader = getClass().getClassLoader(); + classLoader = requireNonNull(getClass().getClassLoader(), + () -> "getClassLoader is null for " + getClass()); } //~ Methods ---------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/util/trace/CalciteLogger.java b/core/src/main/java/org/apache/calcite/util/trace/CalciteLogger.java index 8cb1c504e4ad..06a9f787d538 100644 --- a/core/src/main/java/org/apache/calcite/util/trace/CalciteLogger.java +++ b/core/src/main/java/org/apache/calcite/util/trace/CalciteLogger.java @@ -16,6 +16,7 @@ */ package org.apache.calcite.util.trace; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; /** @@ -62,7 +63,7 @@ public CalciteLogger(Logger logger) { /** * Logs a WARN message with two Object parameters. */ - public void warn(String format, Object arg1, Object arg2) { + public void warn(String format, @Nullable Object arg1, @Nullable Object arg2) { // slf4j already avoids the array creation for 1 or 2 arg invocations logger.warn(format, arg1, arg2); } @@ -70,7 +71,8 @@ public void warn(String format, Object arg1, Object arg2) { /** * Conditionally logs a WARN message with three Object parameters. */ - public void warn(String format, Object arg1, Object arg2, Object arg3) { + public void warn(String format, @Nullable Object arg1, @Nullable Object arg2, + @Nullable Object arg3) { if (logger.isWarnEnabled()) { logger.warn(format, arg1, arg2, arg3); } @@ -79,7 +81,8 @@ public void warn(String format, Object arg1, Object arg2, Object arg3) { /** * Conditionally logs a WARN message with four Object parameters. */ - public void warn(String format, Object arg1, Object arg2, Object arg3, Object arg4) { + public void warn(String format, @Nullable Object arg1, @Nullable Object arg2, + @Nullable Object arg3, @Nullable Object arg4) { if (logger.isWarnEnabled()) { logger.warn(format, arg1, arg2, arg3, arg4); } @@ -96,7 +99,7 @@ public void warn(String format, Object... args) { /** * Logs an INFO message with two Object parameters. */ - public void info(String format, Object arg1, Object arg2) { + public void info(String format, @Nullable Object arg1, @Nullable Object arg2) { // slf4j already avoids the array creation for 1 or 2 arg invocations logger.info(format, arg1, arg2); } @@ -104,7 +107,8 @@ public void info(String format, Object arg1, Object arg2) { /** * Conditionally logs an INFO message with three Object parameters. */ - public void info(String format, Object arg1, Object arg2, Object arg3) { + public void info(String format, @Nullable Object arg1, @Nullable Object arg2, + @Nullable Object arg3) { if (logger.isInfoEnabled()) { logger.info(format, arg1, arg2, arg3); } @@ -113,7 +117,8 @@ public void info(String format, Object arg1, Object arg2, Object arg3) { /** * Conditionally logs an INFO message with four Object parameters. */ - public void info(String format, Object arg1, Object arg2, Object arg3, Object arg4) { + public void info(String format, @Nullable Object arg1, @Nullable Object arg2, + @Nullable Object arg3, @Nullable Object arg4) { if (logger.isInfoEnabled()) { logger.info(format, arg1, arg2, arg3, arg4); } @@ -130,7 +135,7 @@ public void info(String format, Object... args) { /** * Logs a DEBUG message with two Object parameters. */ - public void debug(String format, Object arg1, Object arg2) { + public void debug(String format, @Nullable Object arg1, @Nullable Object arg2) { // slf4j already avoids the array creation for 1 or 2 arg invocations logger.debug(format, arg1, arg2); } @@ -138,7 +143,8 @@ public void debug(String format, Object arg1, Object arg2) { /** * Conditionally logs a DEBUG message with three Object parameters. */ - public void debug(String format, Object arg1, Object arg2, Object arg3) { + public void debug(String format, @Nullable Object arg1, @Nullable Object arg2, + @Nullable Object arg3) { if (logger.isDebugEnabled()) { logger.debug(format, arg1, arg2, arg3); } @@ -147,7 +153,8 @@ public void debug(String format, Object arg1, Object arg2, Object arg3) { /** * Conditionally logs a DEBUG message with four Object parameters. */ - public void debug(String format, Object arg1, Object arg2, Object arg3, Object arg4) { + public void debug(String format, @Nullable Object arg1, @Nullable Object arg2, + @Nullable Object arg3, @Nullable Object arg4) { if (logger.isDebugEnabled()) { logger.debug(format, arg1, arg2, arg3, arg4); } @@ -164,7 +171,7 @@ public void debug(String format, Object... args) { /** * Logs a TRACE message with two Object parameters. */ - public void trace(String format, Object arg1, Object arg2) { + public void trace(String format, @Nullable Object arg1, @Nullable Object arg2) { // slf4j already avoids the array creation for 1 or 2 arg invocations logger.trace(format, arg1, arg2); } @@ -172,7 +179,8 @@ public void trace(String format, Object arg1, Object arg2) { /** * Conditionally logs a TRACE message with three Object parameters. */ - public void trace(String format, Object arg1, Object arg2, Object arg3) { + public void trace(String format, @Nullable Object arg1, @Nullable Object arg2, + @Nullable Object arg3) { if (logger.isTraceEnabled()) { logger.trace(format, arg1, arg2, arg3); } @@ -181,13 +189,14 @@ public void trace(String format, Object arg1, Object arg2, Object arg3) { /** * Conditionally logs a TRACE message with four Object parameters. */ - public void trace(String format, Object arg1, Object arg2, Object arg3, Object arg4) { + public void trace(String format, @Nullable Object arg1, @Nullable Object arg2, + @Nullable Object arg3, @Nullable Object arg4) { if (logger.isTraceEnabled()) { logger.trace(format, arg1, arg2, arg3, arg4); } } - public void trace(String format, Object... args) { + public void trace(String format, @Nullable Object... args) { if (logger.isTraceEnabled()) { logger.trace(format, args); } diff --git a/core/src/test/java/org/apache/calcite/adapter/generate/RangeTable.java b/core/src/test/java/org/apache/calcite/adapter/generate/RangeTable.java index c62ea21ed929..46eb8afd74e0 100644 --- a/core/src/test/java/org/apache/calcite/adapter/generate/RangeTable.java +++ b/core/src/test/java/org/apache/calcite/adapter/generate/RangeTable.java @@ -27,6 +27,8 @@ import org.apache.calcite.schema.impl.AbstractTableQueryable; import org.apache.calcite.sql.type.SqlTypeName; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Map; import java.util.NoSuchElementException; @@ -102,7 +104,7 @@ public RangeTable create( SchemaPlus schema, String name, Map operand, - RelDataType rowType) { + @Nullable RelDataType rowType) { final String columnName = (String) operand.get("column"); final int start = (Integer) operand.get("start"); final int end = (Integer) operand.get("end"); diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterStructsTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterStructsTest.java index 7f9740c242ea..e70699284ae7 100644 --- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterStructsTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterStructsTest.java @@ -37,6 +37,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import org.checkerframework.checker.nullness.qual.Nullable; import org.junit.jupiter.api.Test; import java.util.Collection; @@ -81,7 +82,7 @@ class RelToSqlConverterStructsTest { return ImmutableSet.of(); } - @Override public Expression getExpression(SchemaPlus parentSchema, String name) { + @Override public Expression getExpression(@Nullable SchemaPlus parentSchema, String name) { return null; } @@ -145,8 +146,8 @@ class RelToSqlConverterStructsTest { @Override public boolean rolledUpColumnValidInsideAgg( String column, SqlCall call, - SqlNode parent, - CalciteConnectionConfig config) { + @Nullable SqlNode parent, + @Nullable CalciteConnectionConfig config) { return false; } }; diff --git a/core/src/test/java/org/apache/calcite/schemas/HrClusteredSchema.java b/core/src/test/java/org/apache/calcite/schemas/HrClusteredSchema.java index 32c2cac068bb..08a644304f58 100644 --- a/core/src/test/java/org/apache/calcite/schemas/HrClusteredSchema.java +++ b/core/src/test/java/org/apache/calcite/schemas/HrClusteredSchema.java @@ -34,6 +34,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.Arrays; import java.util.List; @@ -119,7 +121,7 @@ private static class PkClusteredTable extends AbstractTable implements Scannable return typeBuilder.apply(typeFactory); } - @Override public Enumerable scan(final DataContext root) { + @Override public Enumerable<@Nullable Object[]> scan(final DataContext root) { return Linq4j.asEnumerable(data); } diff --git a/core/src/test/java/org/apache/calcite/test/CollectionTypeTest.java b/core/src/test/java/org/apache/calcite/test/CollectionTypeTest.java index b95a69a31b8a..06c0678cde18 100644 --- a/core/src/test/java/org/apache/calcite/test/CollectionTypeTest.java +++ b/core/src/test/java/org/apache/calcite/test/CollectionTypeTest.java @@ -35,6 +35,7 @@ import org.apache.calcite.sql.SqlNode; import org.apache.calcite.sql.type.SqlTypeName; +import org.checkerframework.checker.nullness.qual.Nullable; import org.junit.jupiter.api.Test; import java.sql.Connection; @@ -395,7 +396,7 @@ public Schema.TableType getJdbcTableType() { return Schema.TableType.TABLE; } - public Enumerable scan(DataContext root) { + public Enumerable<@Nullable Object[]> scan(DataContext root) { return new AbstractEnumerable() { public Enumerator enumerator() { return nestedRecordsEnumerator(); @@ -407,9 +408,9 @@ public Enumerator enumerator() { return false; } - @Override public boolean rolledUpColumnValidInsideAgg(String column, - SqlCall call, SqlNode parent, - CalciteConnectionConfig config) { + @Override public boolean rolledUpColumnValidInsideAgg( + String column, SqlCall call, @Nullable SqlNode parent, + @Nullable CalciteConnectionConfig config) { return false; } } @@ -435,7 +436,7 @@ public Schema.TableType getJdbcTableType() { return Schema.TableType.TABLE; } - public Enumerable scan(DataContext root) { + public Enumerable<@Nullable Object[]> scan(DataContext root) { return new AbstractEnumerable() { public Enumerator enumerator() { return nestedRecordsEnumerator(); @@ -448,7 +449,7 @@ public Enumerator enumerator() { } @Override public boolean rolledUpColumnValidInsideAgg(String column, - SqlCall call, SqlNode parent, CalciteConnectionConfig config) { + SqlCall call, @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return false; } } diff --git a/core/src/test/java/org/apache/calcite/test/CountriesTableFunction.java b/core/src/test/java/org/apache/calcite/test/CountriesTableFunction.java index 8740a6823d54..dab24ef9bfe1 100644 --- a/core/src/test/java/org/apache/calcite/test/CountriesTableFunction.java +++ b/core/src/test/java/org/apache/calcite/test/CountriesTableFunction.java @@ -33,6 +33,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + /** A table function that returns all countries in the world. * *

Has same content as @@ -290,7 +292,7 @@ private CountriesTableFunction() {} public static ScannableTable eval(boolean b) { return new ScannableTable() { - public Enumerable scan(DataContext root) { + public Enumerable<@Nullable Object[]> scan(DataContext root) { return Linq4j.asEnumerable(ROWS); }; @@ -317,7 +319,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/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java index 26564ded1fbb..6204a52e87f5 100644 --- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java +++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java @@ -99,6 +99,7 @@ import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Multimap; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hamcrest.Matcher; import org.hamcrest.comparator.ComparatorMatcherBuilder; import org.hsqldb.jdbcDriver; @@ -7965,7 +7966,7 @@ public Table create( SchemaPlus schema, String name, Map operand, - RelDataType rowType) { + @Nullable RelDataType rowType) { final Class clazz; final Object[] array; switch (name) { diff --git a/core/src/test/java/org/apache/calcite/test/ModelTest.java b/core/src/test/java/org/apache/calcite/test/ModelTest.java index 4f54da7f88ac..43c569bf1fe1 100644 --- a/core/src/test/java/org/apache/calcite/test/ModelTest.java +++ b/core/src/test/java/org/apache/calcite/test/ModelTest.java @@ -77,6 +77,7 @@ private ObjectMapper mapper() { + " tables: [\n" + " {\n" + " name: 'time_by_day',\n" + + " factory: 'com.test',\n" + " columns: [\n" + " {\n" + " name: 'time_id'\n" @@ -85,6 +86,7 @@ private ObjectMapper mapper() { + " },\n" + " {\n" + " name: 'sales_fact_1997',\n" + + " factory: 'com.test',\n" + " columns: [\n" + " {\n" + " name: 'time_id'\n" @@ -151,13 +153,14 @@ private ObjectMapper mapper() { + " factory: 'com.acme.MySchemaFactory',\n" + " operand: {a: 'foo', b: [1, 3.5] },\n" + " tables: [\n" - + " { type: 'custom', name: 'T1' },\n" - + " { type: 'custom', name: 'T2', operand: {} },\n" - + " { type: 'custom', name: 'T3', operand: {a: 'foo'} }\n" + + " { type: 'custom', name: 'T1', factory: 'com.test' },\n" + + " { type: 'custom', name: 'T2', factory: 'com.test', operand: {} },\n" + + " { type: 'custom', name: 'T3', factory: 'com.test', operand: {a: 'foo'} }\n" + " ]\n" + " },\n" + " {\n" + " type: 'custom',\n" + + " factory: 'com.acme.MySchemaFactory',\n" + " name: 'has-no-operand'\n" + " }\n" + " ]\n" @@ -230,7 +233,7 @@ private ObjectMapper mapper() { + " } ]\n" + "}"; CalciteAssert.model(model) - .connectThrows("Field 'name' is required in JsonMapSchema"); + .connectThrows("Missing required creator property 'name'"); } @Test void testCustomSchemaWithoutFactory() throws Exception { @@ -243,7 +246,7 @@ private ObjectMapper mapper() { + " } ]\n" + "}"; CalciteAssert.model(model) - .connectThrows("Field 'factory' is required in JsonCustomSchema"); + .connectThrows("Missing required creator property 'factory'"); } /** Tests a model containing a lattice and some views. */ @@ -257,6 +260,7 @@ private ObjectMapper mapper() { + " tables: [\n" + " {\n" + " name: 'time_by_day',\n" + + " factory: 'com.test',\n" + " columns: [\n" + " {\n" + " name: 'time_id'\n" @@ -265,6 +269,7 @@ private ObjectMapper mapper() { + " },\n" + " {\n" + " name: 'sales_fact_1997',\n" + + " factory: 'com.test',\n" + " columns: [\n" + " {\n" + " name: 'time_id'\n" diff --git a/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java b/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java index 55c77ad405f4..6294931a260d 100644 --- a/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java +++ b/core/src/test/java/org/apache/calcite/test/ScannableTableTest.java @@ -416,7 +416,7 @@ private Enumerable superScan(DataContext root) { return super.scan(root); } - @Override public Enumerable + @Override public Enumerable<@Nullable Object[]> scan(final DataContext root) { scanCount.incrementAndGet(); return new AbstractEnumerable() { @@ -507,7 +507,7 @@ public RelDataType getRowType(RelDataTypeFactory typeFactory) { .build(); } - public Enumerable scan(DataContext root) { + public Enumerable<@Nullable Object[]> scan(DataContext root) { return new AbstractEnumerable() { public Enumerator enumerator() { return tens(); @@ -527,7 +527,7 @@ public RelDataType getRowType(RelDataTypeFactory typeFactory) { .build(); } - public Enumerable scan(DataContext root) { + public Enumerable<@Nullable Object[]> scan(DataContext root) { return new AbstractEnumerable() { public Enumerator enumerator() { return beatles(new StringBuilder(), null, null); @@ -556,7 +556,7 @@ public RelDataType getRowType(RelDataTypeFactory typeFactory) { .build(); } - public Enumerable scan(DataContext root, List filters) { + public Enumerable<@Nullable Object[]> scan(DataContext root, List filters) { final Pair filter = getFilter(cooperative, filters); return new AbstractEnumerable() { public Enumerator enumerator() { @@ -587,7 +587,7 @@ public RelDataType getRowType(RelDataTypeFactory typeFactory) { .build(); } - public Enumerable scan(DataContext root, List filters, + public Enumerable<@Nullable Object[]> scan(DataContext root, List filters, final int @Nullable [] projects) { final Pair filter = getFilter(cooperative, filters); return new AbstractEnumerable() { diff --git a/core/src/test/java/org/apache/calcite/test/SqlJsonFunctionsTest.java b/core/src/test/java/org/apache/calcite/test/SqlJsonFunctionsTest.java index c2b23c530a91..79b4df1f9f04 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlJsonFunctionsTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlJsonFunctionsTest.java @@ -60,6 +60,11 @@ class SqlJsonFunctionsTest { is(JsonFunctions.JsonValueContext.withJavaObj(Collections.emptyMap()))); } + @Test void testJsonNullExpression() { + assertJsonValueExpression("null", + is(JsonFunctions.JsonValueContext.withJavaObj(null))); + } + @Test void testJsonApiCommonSyntax() { assertJsonApiCommonSyntax("{\"foo\": \"bar\"}", "$.foo", contextMatches( diff --git a/core/src/test/java/org/apache/calcite/test/StatesTableFunction.java b/core/src/test/java/org/apache/calcite/test/StatesTableFunction.java index 2d72fd0ec771..3d40787ab03d 100644 --- a/core/src/test/java/org/apache/calcite/test/StatesTableFunction.java +++ b/core/src/test/java/org/apache/calcite/test/StatesTableFunction.java @@ -33,6 +33,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + /** A table function that returns states and their boundaries; also national * parks. * @@ -88,7 +90,7 @@ public static ScannableTable parks(boolean b) { private static ScannableTable eval(final Object[][] rows) { return new ScannableTable() { - public Enumerable scan(DataContext root) { + public Enumerable<@Nullable Object[]> scan(DataContext root) { return Linq4j.asEnumerable(rows); } @@ -113,7 +115,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/test/java/org/apache/calcite/test/StreamTest.java b/core/src/test/java/org/apache/calcite/test/StreamTest.java index 11271d72fde2..b106958adfd6 100644 --- a/core/src/test/java/org/apache/calcite/test/StreamTest.java +++ b/core/src/test/java/org/apache/calcite/test/StreamTest.java @@ -41,6 +41,7 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hamcrest.comparator.ComparatorMatcherBuilder; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -377,7 +378,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 false; } } @@ -390,7 +391,7 @@ public OrdersStreamTableFactory() { } public Table create(SchemaPlus schema, String name, - Map operand, RelDataType rowType) { + Map operand, @Nullable RelDataType rowType) { return new OrdersTable(getRowList()); } @@ -419,7 +420,7 @@ public OrdersTable(ImmutableList rows) { this.rows = rows; } - public Enumerable scan(DataContext root) { + public Enumerable<@Nullable Object[]> scan(DataContext root) { return Linq4j.asEnumerable(rows); } @@ -432,7 +433,7 @@ public Enumerable scan(DataContext root) { } @Override public boolean rolledUpColumnValidInsideAgg(String column, - SqlCall call, SqlNode parent, CalciteConnectionConfig config) { + SqlCall call, @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return false; } } @@ -447,7 +448,7 @@ public InfiniteOrdersStreamTableFactory() { } public Table create(SchemaPlus schema, String name, - Map operand, RelDataType rowType) { + Map operand, @Nullable RelDataType rowType) { return new InfiniteOrdersTable(); } } @@ -457,7 +458,7 @@ public Table create(SchemaPlus schema, String name, */ public static class InfiniteOrdersTable extends BaseOrderStreamTable implements StreamableTable { - public Enumerable scan(DataContext root) { + public Enumerable<@Nullable Object[]> scan(DataContext root) { return Linq4j.asEnumerable(() -> new Iterator() { private final String[] items = {"paint", "paper", "brush"}; private int counter = 0; @@ -491,7 +492,7 @@ public OrdersHistoryTable(ImmutableList rows) { this.rows = rows; } - public Enumerable scan(DataContext root) { + public Enumerable<@Nullable Object[]> scan(DataContext root) { return Linq4j.asEnumerable(rows); } } @@ -501,7 +502,7 @@ public Enumerable scan(DataContext root) { */ public static class ProductsTableFactory implements TableFactory { public Table create(SchemaPlus schema, String name, - Map operand, RelDataType rowType) { + Map operand, @Nullable RelDataType rowType) { final Object[][] rows = { {"paint", 1}, {"paper", 0}, @@ -526,7 +527,7 @@ public ProductsTable(ImmutableList rows) { .add("SUPPLIER", SqlTypeName.INTEGER) .build(); - public Enumerable scan(DataContext root) { + public Enumerable<@Nullable Object[]> scan(DataContext root) { return Linq4j.asEnumerable(rows); } @@ -547,7 +548,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 false; } } @@ -589,7 +590,7 @@ public static class ProductsTemporalTable implements TemporalTable { } @Override public boolean rolledUpColumnValidInsideAgg(String column, - SqlCall call, SqlNode parent, CalciteConnectionConfig config) { + SqlCall call, @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return false; } } diff --git a/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReader.java b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReader.java index 93dc2c2b8c88..553b1c3fd0b8 100644 --- a/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReader.java +++ b/core/src/test/java/org/apache/calcite/test/catalog/MockCatalogReader.java @@ -94,6 +94,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.reflect.Type; import java.nio.charset.Charset; import java.util.AbstractList; @@ -436,7 +438,7 @@ protected ModifiableTable(String tableName) { } @Override public boolean rolledUpColumnValidInsideAgg(String column, - SqlCall call, SqlNode parent, CalciteConnectionConfig config) { + SqlCall call, @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { // For testing return call.getKind() != SqlKind.MAX && (parent.getKind() == SqlKind.SELECT || parent.getKind() == SqlKind.FILTER); @@ -1101,7 +1103,7 @@ public RelDistribution getDistribution() { } @Override public boolean rolledUpColumnValidInsideAgg(String column, - SqlCall call, SqlNode parent, CalciteConnectionConfig config) { + SqlCall call, @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { // For testing return call.getKind() != SqlKind.MAX && (parent.getKind() == SqlKind.SELECT || parent.getKind() == SqlKind.FILTER); diff --git a/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java b/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java index 498d2765e005..601ea37b5381 100644 --- a/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java +++ b/core/src/test/java/org/apache/calcite/tools/FrameworksTest.java @@ -494,7 +494,7 @@ public Statistic getStatistic() { ImmutableList.of()); } - public Enumerable scan(DataContext root, List filters, + public Enumerable<@Nullable Object[]> scan(DataContext root, List filters, int @Nullable [] projects) { throw new UnsupportedOperationException(); } diff --git a/core/src/test/java/org/apache/calcite/util/Smalls.java b/core/src/test/java/org/apache/calcite/util/Smalls.java index 77859e15510f..03527b75b711 100644 --- a/core/src/test/java/org/apache/calcite/util/Smalls.java +++ b/core/src/test/java/org/apache/calcite/util/Smalls.java @@ -50,6 +50,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.io.IOException; import java.lang.reflect.Method; import java.math.BigDecimal; @@ -245,7 +247,7 @@ public RelDataType getRowType(RelDataTypeFactory typeFactory) { return typeFactory.builder().add("N", SqlTypeName.BIGINT).build(); } - public Enumerable scan(DataContext root) { + public Enumerable<@Nullable Object[]> scan(DataContext root) { return new AbstractEnumerable() { public Enumerator enumerator() { return new Enumerator() { @@ -291,7 +293,7 @@ public boolean isRolledUp(String column) { } public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, - SqlNode parent, CalciteConnectionConfig config) { + @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return true; } }; @@ -925,7 +927,7 @@ public RelDataType getRowType(RelDataTypeFactory typeFactory) { .build(); } - public Enumerable scan(DataContext root) { + public Enumerable<@Nullable Object[]> scan(DataContext root) { Object[][] rows = {{"abcde"}, {"xyz"}, {content}}; return Linq4j.asEnumerable(rows); } diff --git a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java index deb75f69d303..0fdb4f5ec3b4 100644 --- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java +++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidQuery.java @@ -628,7 +628,7 @@ private double getQueryTypeCostMultiplier() { return Object[].class; } - @Override public Enumerable bind(DataContext dataContext) { + @Override public Enumerable<@Nullable Object[]> bind(DataContext dataContext) { return table.unwrap(ScannableTable.class).scan(dataContext); } diff --git a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java index 0c8c7d6b0512..1461a74bca79 100644 --- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java +++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTable.java @@ -42,6 +42,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import org.checkerframework.checker.nullness.qual.Nullable; import org.joda.time.DateTime; import org.joda.time.Interval; import org.joda.time.chrono.ISOChronology; @@ -180,7 +181,7 @@ public ComplexMetric resolveComplexMetric(String alias, AggregateCall call) { } @Override public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, - SqlNode parent, CalciteConnectionConfig config) { + @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { assert isRolledUp(column); // Our rolled up columns are only allowed in COUNT(DISTINCT ...) aggregate functions. // We only allow this when approximate results are acceptable. diff --git a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTableFactory.java b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTableFactory.java index d1fe59aa051b..77b4d2d67295 100644 --- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTableFactory.java +++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidTableFactory.java @@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; import org.joda.time.Interval; import org.joda.time.chrono.ISOChronology; @@ -49,7 +50,7 @@ private DruidTableFactory() {} // name that is also the same name as a complex metric @Override public Table create(SchemaPlus schema, String name, Map operand, - RelDataType rowType) { + @Nullable RelDataType rowType) { final DruidSchema druidSchema = schema.unwrap(DruidSchema.class); // If "dataSource" operand is present it overrides the table name. final String dataSource = (String) operand.get("dataSource"); diff --git a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvFilterableTable.java b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvFilterableTable.java index 6f0474d5189d..3f61d03737e1 100644 --- a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvFilterableTable.java +++ b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvFilterableTable.java @@ -19,6 +19,7 @@ import org.apache.calcite.DataContext; import org.apache.calcite.adapter.file.CsvEnumerator; import org.apache.calcite.adapter.file.CsvFieldType; +import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.linq4j.AbstractEnumerable; import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.linq4j.Enumerator; @@ -32,9 +33,13 @@ import org.apache.calcite.util.ImmutableIntList; import org.apache.calcite.util.Source; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import static java.util.Objects.requireNonNull; + /** * Table based on a CSV file that can implement simple filtering. * @@ -52,21 +57,22 @@ public CsvFilterableTable(Source source, RelProtoDataType protoRowType) { return "CsvFilterableTable"; } - @Override public Enumerable scan(DataContext root, List filters) { - final List fieldTypes = getFieldTypes(root.getTypeFactory()); - final String[] filterValues = new String[fieldTypes.size()]; + @Override public Enumerable<@Nullable Object[]> scan(DataContext root, List filters) { + JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "typeFactory"); + final List fieldTypes = getFieldTypes(typeFactory); + final @Nullable String[] filterValues = new String[fieldTypes.size()]; filters.removeIf(filter -> addFilter(filter, filterValues)); final List fields = ImmutableIntList.identity(fieldTypes.size()); final AtomicBoolean cancelFlag = DataContext.Variable.CANCEL_FLAG.get(root); - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { return new CsvEnumerator<>(source, cancelFlag, false, filterValues, CsvEnumerator.arrayConverter(fieldTypes, fields, false)); } }; } - private boolean addFilter(RexNode filter, Object[] filterValues) { + private boolean addFilter(RexNode filter, @Nullable Object[] filterValues) { if (filter.isA(SqlKind.AND)) { // We cannot refine(remove) the operands of AND, // it will cause o.a.c.i.TableScanNode.createFilterable filters check failed. diff --git a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvScannableTable.java b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvScannableTable.java index 00827ebb29bf..95a46600f62e 100644 --- a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvScannableTable.java +++ b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvScannableTable.java @@ -19,6 +19,7 @@ import org.apache.calcite.DataContext; import org.apache.calcite.adapter.file.CsvEnumerator; import org.apache.calcite.adapter.file.CsvFieldType; +import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.linq4j.AbstractEnumerable; import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.linq4j.Enumerator; @@ -27,9 +28,13 @@ import org.apache.calcite.util.ImmutableIntList; import org.apache.calcite.util.Source; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import static java.util.Objects.requireNonNull; + /** * Table based on a CSV file. * @@ -47,12 +52,13 @@ public class CsvScannableTable extends CsvTable return "CsvScannableTable"; } - @Override public Enumerable scan(DataContext root) { - final List fieldTypes = getFieldTypes(root.getTypeFactory()); + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { + JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory"); + final List fieldTypes = getFieldTypes(typeFactory); final List fields = ImmutableIntList.identity(fieldTypes.size()); final AtomicBoolean cancelFlag = DataContext.Variable.CANCEL_FLAG.get(root); - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { return new CsvEnumerator<>(source, cancelFlag, false, null, CsvEnumerator.arrayConverter(fieldTypes, fields, false)); } diff --git a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvStreamScannableTable.java b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvStreamScannableTable.java index 2854be93965b..a665daaf4cbf 100644 --- a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvStreamScannableTable.java +++ b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvStreamScannableTable.java @@ -19,6 +19,7 @@ import org.apache.calcite.DataContext; import org.apache.calcite.adapter.file.CsvEnumerator; import org.apache.calcite.adapter.file.CsvFieldType; +import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.linq4j.AbstractEnumerable; import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.linq4j.Enumerator; @@ -29,9 +30,13 @@ import org.apache.calcite.util.ImmutableIntList; import org.apache.calcite.util.Source; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import static java.util.Objects.requireNonNull; + /** * Table based on a CSV file. * @@ -53,12 +58,13 @@ public class CsvStreamScannableTable extends CsvScannableTable return "CsvStreamScannableTable"; } - @Override public Enumerable scan(DataContext root) { - final List fieldTypes = getFieldTypes(root.getTypeFactory()); + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { + JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory"); + final List fieldTypes = getFieldTypes(typeFactory); final List fields = ImmutableIntList.identity(fieldTypes.size()); final AtomicBoolean cancelFlag = DataContext.Variable.CANCEL_FLAG.get(root); - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { return new CsvEnumerator<>(source, cancelFlag, true, null, CsvEnumerator.arrayConverter(fieldTypes, fields, true)); } diff --git a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvStreamTableFactory.java b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvStreamTableFactory.java index 01c25904dd70..49bb2e08232b 100644 --- a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvStreamTableFactory.java +++ b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvStreamTableFactory.java @@ -25,6 +25,8 @@ import org.apache.calcite.util.Source; import org.apache.calcite.util.Sources; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.io.File; import java.util.Map; @@ -41,7 +43,7 @@ public CsvStreamTableFactory() { } @Override public CsvTable create(SchemaPlus schema, String name, - Map operand, RelDataType rowType) { + Map operand, @Nullable RelDataType rowType) { String fileName = (String) operand.get("file"); File file = new File(fileName); final File base = diff --git a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTable.java b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTable.java index 1163cfe6ed09..9af670fe72ba 100644 --- a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTable.java +++ b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTable.java @@ -25,6 +25,8 @@ import org.apache.calcite.schema.impl.AbstractTable; import org.apache.calcite.util.Source; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.List; @@ -33,12 +35,12 @@ */ public abstract class CsvTable extends AbstractTable { protected final Source source; - protected final RelProtoDataType protoRowType; - private RelDataType rowType; - private List fieldTypes; + protected final @Nullable RelProtoDataType protoRowType; + private @Nullable RelDataType rowType; + private @Nullable List fieldTypes; /** Creates a CsvTable. */ - CsvTable(Source source, RelProtoDataType protoRowType) { + CsvTable(Source source, @Nullable RelProtoDataType protoRowType) { this.source = source; this.protoRowType = protoRowType; } diff --git a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTableFactory.java b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTableFactory.java index 1e2c63704805..fed7ddb338e6 100644 --- a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTableFactory.java +++ b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTableFactory.java @@ -25,6 +25,8 @@ import org.apache.calcite.util.Source; import org.apache.calcite.util.Sources; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.io.File; import java.util.Map; @@ -41,7 +43,7 @@ public CsvTableFactory() { } @Override public CsvTable create(SchemaPlus schema, String name, - Map operand, RelDataType rowType) { + Map operand, @Nullable RelDataType rowType) { String fileName = (String) operand.get("file"); final File base = (File) operand.get(ModelHandler.ExtraOperand.BASE_DIRECTORY.camelName); diff --git a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTranslatableTable.java b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTranslatableTable.java index 703c00faee0b..c83125c851dd 100644 --- a/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTranslatableTable.java +++ b/example/csv/src/main/java/org/apache/calcite/adapter/csv/CsvTranslatableTable.java @@ -18,6 +18,7 @@ import org.apache.calcite.DataContext; import org.apache.calcite.adapter.file.CsvEnumerator; +import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.linq4j.AbstractEnumerable; import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.linq4j.Enumerator; @@ -37,6 +38,8 @@ import java.lang.reflect.Type; import java.util.concurrent.atomic.AtomicBoolean; +import static java.util.Objects.requireNonNull; + /** * Table based on a CSV file. */ @@ -58,10 +61,11 @@ public Enumerable project(final DataContext root, final AtomicBoolean cancelFlag = DataContext.Variable.CANCEL_FLAG.get(root); return new AbstractEnumerable() { @Override public Enumerator enumerator() { + JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory"); return new CsvEnumerator<>( source, cancelFlag, - getFieldTypes(root.getTypeFactory()), + getFieldTypes(typeFactory), ImmutableIntList.of(fields)); } }; diff --git a/example/function/src/main/java/org/apache/calcite/example/maze/MazeTable.java b/example/function/src/main/java/org/apache/calcite/example/maze/MazeTable.java index 64052dd1fab9..0818cc0a74ea 100644 --- a/example/function/src/main/java/org/apache/calcite/example/maze/MazeTable.java +++ b/example/function/src/main/java/org/apache/calcite/example/maze/MazeTable.java @@ -28,6 +28,8 @@ import org.apache.calcite.sql.type.SqlTypeName; import org.apache.calcite.util.Util; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.io.PrintWriter; import java.util.Random; import java.util.Set; @@ -85,7 +87,7 @@ public static ScannableTable solve(int width, int height, int seed) { .build(); } - @Override public Enumerable scan(DataContext root) { + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { final Random random = seed >= 0 ? new Random(seed) : new Random(); final Maze maze = new Maze(width, height); final PrintWriter pw = Util.printWriter(System.out); @@ -93,8 +95,8 @@ public static ScannableTable solve(int width, int height, int seed) { if (Maze.DEBUG) { maze.print(pw, true); } - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { final Set solutionSet; if (solution) { solutionSet = maze.solve(0, 0); diff --git a/file/src/main/java/org/apache/calcite/adapter/file/CsvEnumerator.java b/file/src/main/java/org/apache/calcite/adapter/file/CsvEnumerator.java index 46c9923d7b36..6537d87a3ae0 100644 --- a/file/src/main/java/org/apache/calcite/adapter/file/CsvEnumerator.java +++ b/file/src/main/java/org/apache/calcite/adapter/file/CsvEnumerator.java @@ -30,6 +30,8 @@ import au.com.bytecode.opencsv.CSVReader; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; @@ -39,16 +41,18 @@ import java.util.TimeZone; import java.util.concurrent.atomic.AtomicBoolean; +import static org.apache.calcite.linq4j.Nullness.castNonNull; + /** Enumerator that reads from a CSV file. * * @param Row type */ public class CsvEnumerator implements Enumerator { private final CSVReader reader; - private final List filterValues; + private final @Nullable List<@Nullable String> filterValues; private final AtomicBoolean cancelFlag; private final RowConverter rowConverter; - private E current; + private @Nullable E current; private static final FastDateFormat TIME_FORMAT_DATE; private static final FastDateFormat TIME_FORMAT_TIME; @@ -70,7 +74,7 @@ public CsvEnumerator(Source source, AtomicBoolean cancelFlag, } public CsvEnumerator(Source source, AtomicBoolean cancelFlag, boolean stream, - String[] filterValues, RowConverter rowConverter) { + @Nullable String @Nullable [] filterValues, RowConverter rowConverter) { this.cancelFlag = cancelFlag; this.rowConverter = rowConverter; this.filterValues = filterValues == null ? null @@ -97,7 +101,7 @@ private static RowConverter converter(List fieldTypes, } } - public static RowConverter arrayConverter( + public static RowConverter<@Nullable Object[]> arrayConverter( List fieldTypes, List fields, boolean stream) { return new ArrayRowConverter(fieldTypes, fields, stream); } @@ -112,7 +116,7 @@ static RelDataType deduceRowType(JavaTypeFactory typeFactory, Source source, /** Deduces the names and types of a table's columns by reading the first line * of a CSV file. */ public static RelDataType deduceRowType(JavaTypeFactory typeFactory, - Source source, List fieldTypes, Boolean stream) { + Source source, @Nullable List fieldTypes, Boolean stream) { final List types = new ArrayList<>(); final List names = new ArrayList<>(); if (stream) { @@ -170,7 +174,7 @@ static CSVReader openCsv(Source source) throws IOException { } @Override public E current() { - return current; + return castNonNull(current); } @Override public boolean moveNext() { @@ -237,11 +241,11 @@ public static int[] identityList(int n) { * * @param element type */ abstract static class RowConverter { - abstract E convertRow(String[] rows); + abstract E convertRow(@Nullable String[] rows); @SuppressWarnings("JdkObsolete") - protected Object convert(CsvFieldType fieldType, String string) { - if (fieldType == null) { + protected @Nullable Object convert(@Nullable CsvFieldType fieldType, @Nullable String string) { + if (fieldType == null || string == null) { return string; } switch (fieldType) { @@ -318,7 +322,7 @@ protected Object convert(CsvFieldType fieldType, String string) { } /** Array row converter. */ - static class ArrayRowConverter extends RowConverter { + static class ArrayRowConverter extends RowConverter<@Nullable Object[]> { /** Field types. List must not be null, but any element may be null. */ private final List fieldTypes; private final ImmutableIntList fields; @@ -332,7 +336,7 @@ static class ArrayRowConverter extends RowConverter { this.stream = stream; } - @Override public Object[] convertRow(String[] strings) { + @Override public @Nullable Object[] convertRow(@Nullable String[] strings) { if (stream) { return convertStreamRow(strings); } else { @@ -340,8 +344,8 @@ static class ArrayRowConverter extends RowConverter { } } - public Object[] convertNormalRow(String[] strings) { - final Object[] objects = new Object[fields.size()]; + public @Nullable Object[] convertNormalRow(@Nullable String[] strings) { + final @Nullable Object[] objects = new Object[fields.size()]; for (int i = 0; i < fields.size(); i++) { int field = fields.get(i); objects[i] = convert(fieldTypes.get(field), strings[field]); @@ -349,8 +353,8 @@ public Object[] convertNormalRow(String[] strings) { return objects; } - public Object[] convertStreamRow(String[] strings) { - final Object[] objects = new Object[fields.size() + 1]; + public @Nullable Object[] convertStreamRow(@Nullable String[] strings) { + final @Nullable Object[] objects = new Object[fields.size() + 1]; objects[0] = System.currentTimeMillis(); for (int i = 0; i < fields.size(); i++) { int field = fields.get(i); @@ -370,7 +374,7 @@ private SingleColumnRowConverter(CsvFieldType fieldType, int fieldIndex) { this.fieldIndex = fieldIndex; } - @Override public Object convertRow(String[] strings) { + @Override public @Nullable Object convertRow(@Nullable String[] strings) { return convert(fieldType, strings[fieldIndex]); } } diff --git a/file/src/main/java/org/apache/calcite/adapter/file/CsvFieldType.java b/file/src/main/java/org/apache/calcite/adapter/file/CsvFieldType.java index 9f1d28bcbc4a..ff11225a50ac 100644 --- a/file/src/main/java/org/apache/calcite/adapter/file/CsvFieldType.java +++ b/file/src/main/java/org/apache/calcite/adapter/file/CsvFieldType.java @@ -20,6 +20,8 @@ import org.apache.calcite.linq4j.tree.Primitive; import org.apache.calcite.rel.type.RelDataType; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.HashMap; import java.util.Map; @@ -56,7 +58,7 @@ public enum CsvFieldType { } CsvFieldType(Primitive primitive) { - this(primitive.boxClass, primitive.primitiveName); + this(primitive.getBoxClass(), primitive.getPrimitiveName()); } CsvFieldType(Class clazz, String simpleName) { @@ -70,7 +72,7 @@ public RelDataType toType(JavaTypeFactory typeFactory) { return typeFactory.createTypeWithNullability(sqlType, true); } - public static CsvFieldType of(String typeString) { + public static @Nullable CsvFieldType of(String typeString) { return MAP.get(typeString); } } diff --git a/file/src/main/java/org/apache/calcite/adapter/file/CsvTableFactory.java b/file/src/main/java/org/apache/calcite/adapter/file/CsvTableFactory.java index 3809bad5d8ad..82e636cb61fa 100644 --- a/file/src/main/java/org/apache/calcite/adapter/file/CsvTableFactory.java +++ b/file/src/main/java/org/apache/calcite/adapter/file/CsvTableFactory.java @@ -25,6 +25,8 @@ import org.apache.calcite.util.Source; import org.apache.calcite.util.Sources; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.io.File; import java.util.Map; @@ -41,7 +43,7 @@ public CsvTableFactory() { } @Override public CsvTable create(SchemaPlus schema, String name, - Map operand, RelDataType rowType) { + Map operand, @Nullable RelDataType rowType) { String fileName = (String) operand.get("file"); final File base = (File) operand.get(ModelHandler.ExtraOperand.BASE_DIRECTORY.camelName); diff --git a/file/src/main/java/org/apache/calcite/adapter/file/CsvTranslatableTable.java b/file/src/main/java/org/apache/calcite/adapter/file/CsvTranslatableTable.java index 2175f2d332e4..c564df775c42 100644 --- a/file/src/main/java/org/apache/calcite/adapter/file/CsvTranslatableTable.java +++ b/file/src/main/java/org/apache/calcite/adapter/file/CsvTranslatableTable.java @@ -17,6 +17,7 @@ package org.apache.calcite.adapter.file; import org.apache.calcite.DataContext; +import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.linq4j.AbstractEnumerable; import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.linq4j.Enumerator; @@ -36,6 +37,8 @@ import java.lang.reflect.Type; import java.util.concurrent.atomic.AtomicBoolean; +import static java.util.Objects.requireNonNull; + /** * Table based on a CSV file. * @@ -60,8 +63,9 @@ public Enumerable project(final DataContext root, final AtomicBoolean cancelFlag = DataContext.Variable.CANCEL_FLAG.get(root); return new AbstractEnumerable() { @Override public Enumerator enumerator() { + JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory"); return new CsvEnumerator<>(source, cancelFlag, - getFieldTypes(root.getTypeFactory()), ImmutableIntList.of(fields)); + getFieldTypes(typeFactory), ImmutableIntList.of(fields)); } }; } diff --git a/file/src/main/java/org/apache/calcite/adapter/file/JsonEnumerator.java b/file/src/main/java/org/apache/calcite/adapter/file/JsonEnumerator.java index 25fe0ec94f81..256c8e0f587c 100644 --- a/file/src/main/java/org/apache/calcite/adapter/file/JsonEnumerator.java +++ b/file/src/main/java/org/apache/calcite/adapter/file/JsonEnumerator.java @@ -27,6 +27,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -37,12 +39,12 @@ /** * Enumerator that reads from a Object List. */ -public class JsonEnumerator implements Enumerator { +public class JsonEnumerator implements Enumerator<@Nullable Object[]> { - private Enumerator enumerator; + private final Enumerator<@Nullable Object[]> enumerator; - public JsonEnumerator(List list) { - List objs = new ArrayList(); + public JsonEnumerator(List list) { + List<@Nullable Object[]> objs = new ArrayList<>(); for (Object obj : list) { if (obj instanceof Collection) { //noinspection unchecked diff --git a/file/src/main/java/org/apache/calcite/adapter/file/JsonScannableTable.java b/file/src/main/java/org/apache/calcite/adapter/file/JsonScannableTable.java index fe6010ad066e..757b46446f59 100644 --- a/file/src/main/java/org/apache/calcite/adapter/file/JsonScannableTable.java +++ b/file/src/main/java/org/apache/calcite/adapter/file/JsonScannableTable.java @@ -17,12 +17,17 @@ package org.apache.calcite.adapter.file; import org.apache.calcite.DataContext; +import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.linq4j.AbstractEnumerable; import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.linq4j.Enumerator; import org.apache.calcite.schema.ScannableTable; import org.apache.calcite.util.Source; +import org.checkerframework.checker.nullness.qual.Nullable; + +import static java.util.Objects.requireNonNull; + /** * Table based on a JSON file. * @@ -42,10 +47,11 @@ public JsonScannableTable(Source source) { return "JsonScannableTable"; } - @Override public Enumerable scan(DataContext root) { - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { - return new JsonEnumerator(getDataList(root.getTypeFactory())); + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { + JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory"); + return new JsonEnumerator(getDataList(typeFactory)); } }; } diff --git a/file/src/main/java/org/apache/calcite/adapter/file/JsonTable.java b/file/src/main/java/org/apache/calcite/adapter/file/JsonTable.java index 17f2da8bdf7d..e26f81d8c325 100644 --- a/file/src/main/java/org/apache/calcite/adapter/file/JsonTable.java +++ b/file/src/main/java/org/apache/calcite/adapter/file/JsonTable.java @@ -24,6 +24,8 @@ import org.apache.calcite.schema.impl.AbstractTable; import org.apache.calcite.util.Source; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -31,8 +33,8 @@ */ public class JsonTable extends AbstractTable { private final Source source; - private RelDataType rowType; - protected List dataList; + private @Nullable RelDataType rowType; + protected @Nullable List dataList; public JsonTable(Source source) { this.source = source; diff --git a/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleScannableTable.java b/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleScannableTable.java index ddeeab2b25fb..aa31c3766972 100644 --- a/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleScannableTable.java +++ b/geode/src/main/java/org/apache/calcite/adapter/geode/simple/GeodeSimpleScannableTable.java @@ -27,6 +27,8 @@ import org.apache.geode.cache.client.ClientCache; +import org.checkerframework.checker.nullness.qual.Nullable; + import static org.apache.calcite.adapter.geode.util.GeodeUtils.convertToRowValues; /** @@ -55,11 +57,11 @@ public GeodeSimpleScannableTable(String regionName, RelDataType relDataType, return relDataType; } - @Override public Enumerable scan(DataContext root) { - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { - return new GeodeSimpleEnumerator(clientCache, regionName) { - @Override public Object[] convert(Object obj) { + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { + return new GeodeSimpleEnumerator<@Nullable Object[]>(clientCache, regionName) { + @Override public @Nullable Object[] convert(Object obj) { Object values = convertToRowValues(relDataType.getFieldList(), obj); if (values instanceof Object[]) { return (Object[]) values; diff --git a/gradle.properties b/gradle.properties index 6f35d30c1a7c..6b2305680458 100644 --- a/gradle.properties +++ b/gradle.properties @@ -86,7 +86,6 @@ elasticsearch.version=7.0.1 embedded-redis.version=0.6 errorprone.version=2.4.0 esri-geometry-api.version=2.2.0 -findbugs.jsr305.version=3.0.1 foodmart-data-hsqldb.version=0.3 foodmart-data-json.version=0.4 foodmart-queries.version=0.4.1 diff --git a/kafka/src/main/java/org/apache/calcite/adapter/kafka/KafkaMessageEnumerator.java b/kafka/src/main/java/org/apache/calcite/adapter/kafka/KafkaMessageEnumerator.java index 8069aeeab47e..af091a58d3ae 100644 --- a/kafka/src/main/java/org/apache/calcite/adapter/kafka/KafkaMessageEnumerator.java +++ b/kafka/src/main/java/org/apache/calcite/adapter/kafka/KafkaMessageEnumerator.java @@ -23,11 +23,15 @@ import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.time.Duration; import java.util.ArrayDeque; import java.util.Deque; import java.util.concurrent.atomic.AtomicBoolean; +import static java.util.Objects.requireNonNull; + /** * Enumerator to read data from {@link Consumer}, * and converted into SQL rows with {@link KafkaRowConverter}. @@ -37,14 +41,14 @@ * @param Type for Kafka message value, * refer to {@link ConsumerConfig#VALUE_DESERIALIZER_CLASS_CONFIG}; */ -public class KafkaMessageEnumerator implements Enumerator { +public class KafkaMessageEnumerator implements Enumerator<@Nullable Object[]> { final Consumer consumer; final KafkaRowConverter rowConverter; private final AtomicBoolean cancelFlag; //runtime private final Deque> bufferedRecords = new ArrayDeque<>(); - private ConsumerRecord curRecord; + private @Nullable ConsumerRecord curRecord; KafkaMessageEnumerator(final Consumer consumer, final KafkaRowConverter rowConverter, @@ -58,7 +62,7 @@ public class KafkaMessageEnumerator implements Enumerator { * It returns an Array of Object, with each element represents a field of row. */ @Override public Object[] current() { - return rowConverter.toRow(curRecord); + return rowConverter.toRow(requireNonNull(curRecord, "curRecord")); } @Override public boolean moveNext() { diff --git a/kafka/src/main/java/org/apache/calcite/adapter/kafka/KafkaStreamTable.java b/kafka/src/main/java/org/apache/calcite/adapter/kafka/KafkaStreamTable.java index 334e7a6baaea..ea5f257bcb0d 100644 --- a/kafka/src/main/java/org/apache/calcite/adapter/kafka/KafkaStreamTable.java +++ b/kafka/src/main/java/org/apache/calcite/adapter/kafka/KafkaStreamTable.java @@ -39,6 +39,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Collections; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; @@ -56,10 +58,10 @@ public class KafkaStreamTable implements ScannableTable, StreamableTable { this.tableOptions = tableOptions; } - @Override public Enumerable scan(final DataContext root) { + @Override public Enumerable<@Nullable Object[]> scan(final DataContext root) { final AtomicBoolean cancelFlag = DataContext.Variable.CANCEL_FLAG.get(root); - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { if (tableOptions.getConsumer() != null) { return new KafkaMessageEnumerator(tableOptions.getConsumer(), tableOptions.getRowConverter(), cancelFlag); @@ -99,8 +101,8 @@ public class KafkaStreamTable implements ScannableTable, StreamableTable { } @Override public boolean rolledUpColumnValidInsideAgg(final String column, final SqlCall call, - final SqlNode parent, - final CalciteConnectionConfig config) { + final @Nullable SqlNode parent, + final @Nullable CalciteConnectionConfig config) { return false; } diff --git a/kafka/src/main/java/org/apache/calcite/adapter/kafka/KafkaTableFactory.java b/kafka/src/main/java/org/apache/calcite/adapter/kafka/KafkaTableFactory.java index 2271d4cb5047..51441bd17f21 100644 --- a/kafka/src/main/java/org/apache/calcite/adapter/kafka/KafkaTableFactory.java +++ b/kafka/src/main/java/org/apache/calcite/adapter/kafka/KafkaTableFactory.java @@ -23,6 +23,8 @@ import org.apache.kafka.clients.consumer.Consumer; import org.apache.kafka.clients.consumer.OffsetResetStrategy; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.lang.reflect.InvocationTargetException; import java.util.Locale; import java.util.Map; @@ -38,7 +40,7 @@ public KafkaTableFactory() { @Override public KafkaStreamTable create(SchemaPlus schema, String name, Map operand, - RelDataType rowType) { + @Nullable RelDataType rowType) { final KafkaTableOptions tableOptionBuilder = new KafkaTableOptions(); tableOptionBuilder.setBootstrapServers( diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java b/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java index 883352f7c80c..964df314dd02 100644 --- a/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java +++ b/linq4j/src/main/java/org/apache/calcite/linq4j/Linq4j.java @@ -205,8 +205,8 @@ private static Enumerator listEnumerator(List list) { * @param Element type * @return Enumerator */ - public static Enumerator transform(Enumerator enumerator, - final Function1 func) { + public static Enumerator transform(Enumerator enumerator, + final Function1 func) { return new TransformedEnumerator(enumerator) { @Override protected E transform(F from) { return func.apply(from); diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/TransformedEnumerator.java b/linq4j/src/main/java/org/apache/calcite/linq4j/TransformedEnumerator.java index 6fc726d4a56d..f731529556f0 100644 --- a/linq4j/src/main/java/org/apache/calcite/linq4j/TransformedEnumerator.java +++ b/linq4j/src/main/java/org/apache/calcite/linq4j/TransformedEnumerator.java @@ -23,9 +23,9 @@ * @param Element type */ public abstract class TransformedEnumerator implements Enumerator { - protected final Enumerator enumerator; + protected final Enumerator enumerator; - protected TransformedEnumerator(Enumerator enumerator) { + protected TransformedEnumerator(Enumerator enumerator) { this.enumerator = enumerator; } diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/function/Functions.java b/linq4j/src/main/java/org/apache/calcite/linq4j/function/Functions.java index 94dab2e5b9eb..c3b9877a6bb5 100644 --- a/linq4j/src/main/java/org/apache/calcite/linq4j/function/Functions.java +++ b/linq4j/src/main/java/org/apache/calcite/linq4j/function/Functions.java @@ -76,7 +76,7 @@ private Functions() {} private static final EqualityComparer IDENTITY_COMPARER = new IdentityEqualityComparer(); - private static final EqualityComparer ARRAY_COMPARER = + private static final EqualityComparer<@Nullable Object[]> ARRAY_COMPARER = new ArrayEqualityComparer(); private static final Function1 CONSTANT_NULL_FUNCTION1 = @@ -488,12 +488,12 @@ public static EqualityComparer selectorComparer( /** Array equality comparer. */ private static class ArrayEqualityComparer - implements EqualityComparer { - @Override public boolean equal(Object[] v1, Object[] v2) { + implements EqualityComparer<@Nullable Object[]> { + @Override public boolean equal(@Nullable Object[] v1, @Nullable Object[] v2) { return Arrays.deepEquals(v1, v2); } - @Override public int hashCode(Object[] t) { + @Override public int hashCode(@Nullable Object[] t) { return Arrays.deepHashCode(t); } } diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java index ccab3e5bde15..e604a31046fa 100644 --- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java +++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Expressions.java @@ -820,7 +820,7 @@ public static BinaryExpression exclusiveOrAssign(Expression left, /** * Creates a MemberExpression that represents accessing a field. */ - public static MemberExpression field(Expression expression, Field field) { + public static MemberExpression field(@Nullable Expression expression, Field field) { return makeMemberAccess(expression, Types.field(field)); } diff --git a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Primitive.java b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Primitive.java index 004b97c58517..0e89bdeebed6 100644 --- a/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Primitive.java +++ b/linq4j/src/main/java/org/apache/calcite/linq4j/tree/Primitive.java @@ -16,6 +16,7 @@ */ package org.apache.calcite.linq4j.tree; +import org.apiguardian.api.API; import org.checkerframework.checker.nullness.qual.Nullable; import java.lang.reflect.Array; @@ -255,6 +256,27 @@ public static Class unbox(Class type) { return primitive == null ? type : requireNonNull(primitive.primitiveClass); } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + public Class getPrimitiveClass() { + return requireNonNull(primitiveClass, () -> "no primitiveClass for " + this); + } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + public Class getBoxClass() { + return requireNonNull(boxClass, () -> "no boxClass for " + this); + } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + public String getPrimitiveName() { + return requireNonNull(primitiveName, () -> "no primitiveName for " + this); + } + + @API(since = "1.27", status = API.Status.EXPERIMENTAL) + public String getBoxName() { + return requireNonNull(boxName, () -> "no boxName for " + this); + } + /** * Adapts a primitive array into a {@link List}. For example, * {@code asList(new double[2])} returns a {@code List}. diff --git a/pig/src/main/java/org/apache/calcite/adapter/pig/PigTableFactory.java b/pig/src/main/java/org/apache/calcite/adapter/pig/PigTableFactory.java index 7604f3a7e9fd..70a5c5e8fdd7 100644 --- a/pig/src/main/java/org/apache/calcite/adapter/pig/PigTableFactory.java +++ b/pig/src/main/java/org/apache/calcite/adapter/pig/PigTableFactory.java @@ -21,6 +21,8 @@ import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.schema.TableFactory; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.io.File; import java.util.List; import java.util.Map; @@ -37,7 +39,7 @@ public PigTableFactory() { @SuppressWarnings("unchecked") @Override public PigTable create(SchemaPlus schema, String name, - Map operand, RelDataType rowType) { + Map operand, @Nullable RelDataType rowType) { String fileName = (String) operand.get("file"); File file = new File(fileName); final File base = diff --git a/piglet/src/main/java/org/apache/calcite/piglet/PigTable.java b/piglet/src/main/java/org/apache/calcite/piglet/PigTable.java index 5a4a3c628057..0ab303a5aeaf 100644 --- a/piglet/src/main/java/org/apache/calcite/piglet/PigTable.java +++ b/piglet/src/main/java/org/apache/calcite/piglet/PigTable.java @@ -31,6 +31,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; /** @@ -68,7 +70,7 @@ public static RelOptTable createRelOptTable(RelOptSchema schema, return DUMMY_STATISTICS; } - @Override public Enumerable scan(final DataContext root) { + @Override public Enumerable<@Nullable Object[]> scan(final DataContext root) { return null; } } diff --git a/plus/src/main/java/org/apache/calcite/adapter/os/DuTableFunction.java b/plus/src/main/java/org/apache/calcite/adapter/os/DuTableFunction.java index 3a0a72369b45..75bdc29ba5eb 100644 --- a/plus/src/main/java/org/apache/calcite/adapter/os/DuTableFunction.java +++ b/plus/src/main/java/org/apache/calcite/adapter/os/DuTableFunction.java @@ -32,6 +32,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Table function that executes the OS "du" ("disk usage") command * to compute file sizes. @@ -41,7 +43,7 @@ private DuTableFunction() {} public static ScannableTable eval(boolean b) { return new ScannableTable() { - @Override public Enumerable scan(DataContext root) { + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { return Processes.processLines("du", "-ak") .select(a0 -> { final String[] fields = a0.split("\t"); @@ -69,7 +71,7 @@ public static ScannableTable eval(boolean b) { } @Override public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, - SqlNode parent, CalciteConnectionConfig config) { + @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return true; } }; diff --git a/plus/src/main/java/org/apache/calcite/adapter/os/FilesTableFunction.java b/plus/src/main/java/org/apache/calcite/adapter/os/FilesTableFunction.java index c02cd8801a6a..5efb150547c8 100644 --- a/plus/src/main/java/org/apache/calcite/adapter/os/FilesTableFunction.java +++ b/plus/src/main/java/org/apache/calcite/adapter/os/FilesTableFunction.java @@ -17,6 +17,7 @@ package org.apache.calcite.adapter.os; import org.apache.calcite.DataContext; +import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.config.CalciteConnectionConfig; import org.apache.calcite.linq4j.AbstractEnumerable; import org.apache.calcite.linq4j.Enumerable; @@ -35,10 +36,14 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.math.BigDecimal; import java.util.Arrays; import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Table function that executes the OS "find" command to find files under a * particular path. @@ -144,8 +149,9 @@ private Enumerable sourceMacOs() { return Processes.processLines('\n', args); } - @Override public Enumerable scan(DataContext root) { - final RelDataType rowType = getRowType(root.getTypeFactory()); + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { + JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory"); + final RelDataType rowType = getRowType(typeFactory); final List fieldNames = ImmutableList.copyOf(rowType.getFieldNames()); final String osName = System.getProperty("os.name"); @@ -159,14 +165,14 @@ private Enumerable sourceMacOs() { default: enumerable = sourceLinux(); } - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { final Enumerator e = enumerable.enumerator(); - return new Enumerator() { - Object[] current; + return new Enumerator<@Nullable Object[]>() { + @Nullable Object @Nullable [] current; @Override public Object[] current() { - return current; + return requireNonNull(current, "current"); } @Override public boolean moveNext() { @@ -188,7 +194,7 @@ private Enumerable sourceMacOs() { case "Mac OS X": // Strip leading "./" String path = (String) current[14]; - if (path.equals(".")) { + if (".".equals(path)) { current[14] = path = ""; current[3] = 0; // depth } else if (path.startsWith("./")) { @@ -208,9 +214,9 @@ private Enumerable sourceMacOs() { // Make type values more like those on Linux final String type = (String) current[19]; - current[19] = type.equals("/") ? "d" - : type.equals("") || type.equals("*") ? "f" - : type.equals("@") ? "l" + current[19] = "/".equals(type) ? "d" + : "".equals(type) || "*".equals(type) ? "f" + : "@".equals(type) ? "l" : type; break; default: @@ -275,7 +281,7 @@ private Object field(String field, String value) { } @Override public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, - SqlNode parent, CalciteConnectionConfig config) { + @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return true; } }; diff --git a/plus/src/main/java/org/apache/calcite/adapter/os/GitCommitsTableFunction.java b/plus/src/main/java/org/apache/calcite/adapter/os/GitCommitsTableFunction.java index e92751f3f2f7..6b5fa2a1ee5a 100644 --- a/plus/src/main/java/org/apache/calcite/adapter/os/GitCommitsTableFunction.java +++ b/plus/src/main/java/org/apache/calcite/adapter/os/GitCommitsTableFunction.java @@ -34,6 +34,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.NoSuchElementException; /** @@ -53,17 +55,17 @@ private GitCommitsTableFunction() {} public static ScannableTable eval(boolean b) { return new ScannableTable() { - @Override public Enumerable scan(DataContext root) { + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { final Enumerable enumerable = Processes.processLines("git", "log", "--pretty=raw"); - return new AbstractEnumerable() { - @Override public Enumerator enumerator() { + return new AbstractEnumerable<@Nullable Object[]>() { + @Override public Enumerator<@Nullable Object[]> enumerator() { final Enumerator e = enumerable.enumerator(); - return new Enumerator() { - private Object[] objects; + return new Enumerator<@Nullable Object[]>() { + private @Nullable Object @Nullable [] objects; private final StringBuilder b = new StringBuilder(); - @Override public Object[] current() { + @Override public @Nullable Object[] current() { if (objects == null) { throw new NoSuchElementException(); } @@ -166,7 +168,7 @@ public static ScannableTable eval(boolean b) { } @Override public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, - SqlNode parent, CalciteConnectionConfig config) { + @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return true; } }; diff --git a/plus/src/main/java/org/apache/calcite/adapter/os/JpsTableFunction.java b/plus/src/main/java/org/apache/calcite/adapter/os/JpsTableFunction.java index fda75aa7378d..8380773a6e24 100644 --- a/plus/src/main/java/org/apache/calcite/adapter/os/JpsTableFunction.java +++ b/plus/src/main/java/org/apache/calcite/adapter/os/JpsTableFunction.java @@ -32,6 +32,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + /** * Table function that executes the OS "jps" ("Java Virtual Machine Process * Status Tool") command to list all java processes of a user. @@ -42,7 +44,7 @@ private JpsTableFunction() { public static ScannableTable eval(boolean b) { return new ScannableTable() { - @Override public Enumerable scan(DataContext root) { + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { return Processes.processLines("jps", "-mlvV") .select(a0 -> { final String[] fields = a0.split(" "); @@ -70,7 +72,7 @@ public static ScannableTable eval(boolean b) { } @Override public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, - SqlNode parent, CalciteConnectionConfig config) { + @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return true; } }; diff --git a/plus/src/main/java/org/apache/calcite/adapter/os/PsTableFunction.java b/plus/src/main/java/org/apache/calcite/adapter/os/PsTableFunction.java index 5962c6b6c941..49102b5f3e9d 100644 --- a/plus/src/main/java/org/apache/calcite/adapter/os/PsTableFunction.java +++ b/plus/src/main/java/org/apache/calcite/adapter/os/PsTableFunction.java @@ -17,6 +17,7 @@ package org.apache.calcite.adapter.os; import org.apache.calcite.DataContext; +import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.avatica.util.TimeUnit; import org.apache.calcite.config.CalciteConnectionConfig; import org.apache.calcite.linq4j.Enumerable; @@ -35,10 +36,14 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static java.util.Objects.requireNonNull; + /** * Table function that executes the OS "ps" command * to list processes. @@ -53,8 +58,9 @@ private PsTableFunction() {} public static ScannableTable eval(boolean b) { return new ScannableTable() { - @Override public Enumerable scan(DataContext root) { - final RelDataType rowType = getRowType(root.getTypeFactory()); + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { + JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory"); + final RelDataType rowType = getRowType(typeFactory); final List fieldNames = ImmutableList.copyOf(rowType.getFieldNames()); final String[] args; @@ -171,7 +177,7 @@ private Object field(String field, String value) { } @Override public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, - SqlNode parent, CalciteConnectionConfig config) { + @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return true; } }; diff --git a/plus/src/main/java/org/apache/calcite/adapter/os/StdinTableFunction.java b/plus/src/main/java/org/apache/calcite/adapter/os/StdinTableFunction.java index 26e36cd3ca99..624b07853460 100644 --- a/plus/src/main/java/org/apache/calcite/adapter/os/StdinTableFunction.java +++ b/plus/src/main/java/org/apache/calcite/adapter/os/StdinTableFunction.java @@ -34,6 +34,8 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -58,7 +60,7 @@ public static ScannableTable eval(boolean b) { final BufferedReader br = new BufferedReader(in); @Override public Enumerator enumerator() { return new Enumerator() { - String line; + @Nullable String line; int i; @Override public Object[] current() { @@ -114,7 +116,7 @@ public static ScannableTable eval(boolean b) { } @Override public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, - SqlNode parent, CalciteConnectionConfig config) { + @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return true; } }; diff --git a/plus/src/main/java/org/apache/calcite/adapter/os/VmstatTableFunction.java b/plus/src/main/java/org/apache/calcite/adapter/os/VmstatTableFunction.java index 042b715b481a..6b800f60aeb5 100644 --- a/plus/src/main/java/org/apache/calcite/adapter/os/VmstatTableFunction.java +++ b/plus/src/main/java/org/apache/calcite/adapter/os/VmstatTableFunction.java @@ -17,6 +17,7 @@ package org.apache.calcite.adapter.os; import org.apache.calcite.DataContext; +import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.config.CalciteConnectionConfig; import org.apache.calcite.linq4j.Enumerable; import org.apache.calcite.linq4j.function.Function1; @@ -34,8 +35,12 @@ import com.google.common.collect.ImmutableList; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.List; +import static java.util.Objects.requireNonNull; + /** * Table function that executes the OS "vmstat" command * to share memory statistics. @@ -46,8 +51,9 @@ private VmstatTableFunction() {} public static ScannableTable eval(boolean b) { return new ScannableTable() { - @Override public Enumerable scan(DataContext root) { - final RelDataType rowType = getRowType(root.getTypeFactory()); + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { + JavaTypeFactory typeFactory = requireNonNull(root.getTypeFactory(), "root.getTypeFactory"); + final RelDataType rowType = getRowType(typeFactory); final List fieldNames = ImmutableList.copyOf(rowType.getFieldNames()); final String[] args; @@ -162,7 +168,7 @@ private Object field(@SuppressWarnings("unused") String field, String value) { } @Override public boolean rolledUpColumnValidInsideAgg(String column, SqlCall call, - SqlNode parent, CalciteConnectionConfig config) { + @Nullable SqlNode parent, @Nullable CalciteConnectionConfig config) { return true; } }; diff --git a/plus/src/main/java/org/apache/calcite/adapter/tpcds/TpcdsSchema.java b/plus/src/main/java/org/apache/calcite/adapter/tpcds/TpcdsSchema.java index 68840bad5ca1..e0253e834f7d 100644 --- a/plus/src/main/java/org/apache/calcite/adapter/tpcds/TpcdsSchema.java +++ b/plus/src/main/java/org/apache/calcite/adapter/tpcds/TpcdsSchema.java @@ -43,6 +43,8 @@ import com.teradata.tpcds.column.Column; import com.teradata.tpcds.column.ColumnType; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -109,7 +111,7 @@ public TpcdsSchema(double scaleFactor) { return tableMap; } - private static Object convert(String string, Column column) { + private static @Nullable Object convert(@Nullable String string, Column column) { if (string == null) { return null; } @@ -154,9 +156,9 @@ private class TpcdsQueryableTable @Override public Queryable asQueryable(final QueryProvider queryProvider, final SchemaPlus schema, final String tableName) { //noinspection unchecked - return (Queryable) new AbstractTableQueryable(queryProvider, + return (Queryable) new AbstractTableQueryable<@Nullable Object[]>(queryProvider, schema, this, tableName) { - @Override public Enumerator enumerator() { + @Override public Enumerator<@Nullable Object[]> enumerator() { final Session session = Session.getDefaultSession() .withTable(tpcdsTable) @@ -164,14 +166,14 @@ private class TpcdsQueryableTable final Results results = Results.constructResults(tpcdsTable, session); return Linq4j.asEnumerable(results) .selectMany( - new Function1>, Enumerable>() { + new Function1>, Enumerable<@Nullable Object[]>>() { final Column[] columns = tpcdsTable.getColumns(); - @Override public Enumerable apply( - List> inRows) { - final List rows = new ArrayList<>(); - for (List strings : inRows) { - final Object[] values = new Object[columns.length]; + @Override public Enumerable<@Nullable Object[]> apply( + List> inRows) { + final List<@Nullable Object[]> rows = new ArrayList<>(); + for (List<@Nullable String> strings : inRows) { + final @Nullable Object[] values = new Object[columns.length]; for (int i = 0; i < strings.size(); i++) { values[i] = convert(strings.get(i), columns[i]); } diff --git a/plus/src/main/java/org/apache/calcite/chinook/PreferredAlbumsTableFactory.java b/plus/src/main/java/org/apache/calcite/chinook/PreferredAlbumsTableFactory.java index 801eae898941..d94b95476bc5 100644 --- a/plus/src/main/java/org/apache/calcite/chinook/PreferredAlbumsTableFactory.java +++ b/plus/src/main/java/org/apache/calcite/chinook/PreferredAlbumsTableFactory.java @@ -30,6 +30,8 @@ import com.google.common.collect.DiscreteDomain; import com.google.common.collect.Range; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Map; /** @@ -45,7 +47,7 @@ public class PreferredAlbumsTableFactory implements TableFactory operand, - RelDataType rowType) { + @Nullable RelDataType rowType) { return new AbstractQueryableTable(Integer.class) { @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) { return typeFactory.builder().add("ID", SqlTypeName.INTEGER).build(); diff --git a/plus/src/main/java/org/apache/calcite/chinook/PreferredGenresTableFactory.java b/plus/src/main/java/org/apache/calcite/chinook/PreferredGenresTableFactory.java index 30e6b0b70d4a..9881efc01d7c 100644 --- a/plus/src/main/java/org/apache/calcite/chinook/PreferredGenresTableFactory.java +++ b/plus/src/main/java/org/apache/calcite/chinook/PreferredGenresTableFactory.java @@ -30,6 +30,8 @@ import com.google.common.collect.DiscreteDomain; import com.google.common.collect.Range; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Map; /** @@ -45,7 +47,7 @@ public class PreferredGenresTableFactory implements TableFactory operand, - RelDataType rowType) { + @Nullable RelDataType rowType) { return new AbstractQueryableTable(Integer.class) { @Override public RelDataType getRowType(RelDataTypeFactory typeFactory) { return typeFactory.builder().add("ID", SqlTypeName.INTEGER).build(); diff --git a/redis/src/main/java/org/apache/calcite/adapter/redis/RedisTable.java b/redis/src/main/java/org/apache/calcite/adapter/redis/RedisTable.java index f6ddbdf9f402..ddb3587958de 100644 --- a/redis/src/main/java/org/apache/calcite/adapter/redis/RedisTable.java +++ b/redis/src/main/java/org/apache/calcite/adapter/redis/RedisTable.java @@ -30,6 +30,8 @@ import com.google.common.collect.ImmutableMap; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -100,7 +102,7 @@ static Table create( return create(schema, tableName, redisConfig, protoRowType); } - @Override public Enumerable scan(DataContext root) { + @Override public Enumerable<@Nullable Object[]> scan(DataContext root) { return new AbstractEnumerable() { @Override public Enumerator enumerator() { return new RedisEnumerator(redisConfig, schema, tableName); diff --git a/redis/src/main/java/org/apache/calcite/adapter/redis/RedisTableFactory.java b/redis/src/main/java/org/apache/calcite/adapter/redis/RedisTableFactory.java index 962ad6304f18..de4042c71c60 100644 --- a/redis/src/main/java/org/apache/calcite/adapter/redis/RedisTableFactory.java +++ b/redis/src/main/java/org/apache/calcite/adapter/redis/RedisTableFactory.java @@ -23,6 +23,8 @@ import org.apache.calcite.schema.Table; import org.apache.calcite.schema.TableFactory; +import org.checkerframework.checker.nullness.qual.Nullable; + import java.util.Map; /** @@ -39,7 +41,7 @@ private RedisTableFactory() { // name that is also the same name as a complex metric @Override public Table create(SchemaPlus schema, String tableName, Map operand, - RelDataType rowType) { + @Nullable RelDataType rowType) { final RedisSchema redisSchema = schema.unwrap(RedisSchema.class); final RelProtoDataType protoRowType = rowType != null ? RelDataTypeImpl.proto(rowType) : null;