You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by al...@apache.org on 2022/03/24 14:42:03 UTC
[ignite] branch master updated: IGNITE-15436 Calcite-based SQL engine - Fixes #9855.
This is an automated email from the ASF dual-hosted git repository.
alexpl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 49e063c IGNITE-15436 Calcite-based SQL engine - Fixes #9855.
49e063c is described below
commit 49e063cb3ce748d4f6caa1dea66ae1f4fd21997d
Author: Aleksey Plekhanov <pl...@gmail.com>
AuthorDate: Thu Mar 24 17:32:04 2022 +0300
IGNITE-15436 Calcite-based SQL engine - Fixes #9855.
Experimental, Apache Calcite based SQL engine:
https://cwiki.apache.org/confluence/display/IGNITE/IEP-37%3A+New+query+execution+engine
See modules/calcite/README.txt file for configuration instructions.
Co-authored-by: Igor Seliverstov <gv...@gmail.com>
Co-authored-by: rkondakov <ko...@mail.ru>
Co-authored-by: Andrey V. Mashenkov <an...@gmail.com>
Co-authored-by: Taras Ledkov <tl...@gridgain.com>
Co-authored-by: korlov42 <ko...@gridgain.com>
Co-authored-by: Evgeniy Stanilovskiy <st...@gmail.com>
Co-authored-by: Yuriy Gerzhedovich <yg...@gridgain.com>
Co-authored-by: Ivan Daschinskiy <iv...@apache.org>
Co-authored-by: Berkof <sa...@mail.ru>
Co-authored-by: Pavel Pereslegin <xx...@gmail.com>
Co-authored-by: Vladimir Steshin <vl...@gmail.com>
Co-authored-by: Vladimir Ermakov <85...@users.noreply.github.com>
Signed-off-by: Aleksey Plekhanov <pl...@gmail.com>
---
modules/benchmarks/pom.xml | 12 +
.../benchmarks/jmh/sql/JmhSqlBenchmark.java | 285 +
modules/calcite/README.txt | 38 +
modules/calcite/pom.xml | 312 +
modules/calcite/src/main/codegen/config.fmpp | 691 +
.../src/main/codegen/includes/parserImpls.ftl | 620 +
.../apache/calcite/plan/volcano/VolcanoUtils.java} | 29 +-
.../calcite/CalciteQueryEngineConfiguration.java} | 46 +-
.../org/apache/ignite/calcite/package-info.java | 22 +
.../query/calcite/CalciteQueryProcessor.java | 442 +
.../internal/processors/query/calcite/Query.java | 242 +
.../processors/query/calcite/QueryRegistry.java | 54 +
.../query/calcite/QueryRegistryImpl.java | 108 +
.../query/calcite/RemoteFragmentKey.java} | 69 +-
.../processors/query/calcite/RootQuery.java | 405 +
.../processors/query/calcite/RunningFragment.java | 79 +
.../query/calcite/exec/AbstractIndexScan.java | 165 +
.../query/calcite/exec/ArrayRowHandler.java | 77 +
.../calcite/exec/ClosableIteratorsHolder.java | 165 +
.../query/calcite/exec/ExchangeService.java | 93 +
.../query/calcite/exec/ExchangeServiceImpl.java | 316 +
.../calcite/exec/ExecutionCancelledException.java} | 28 +-
.../query/calcite/exec/ExecutionContext.java | 327 +
.../query/calcite/exec/ExecutionService.java} | 33 +-
.../query/calcite/exec/ExecutionServiceImpl.java | 757 +
.../processors/query/calcite/exec/IndexScan.java | 318 +
.../query/calcite/exec/LogicalRelImplementor.java | 775 +
.../query/calcite/exec/MailboxRegistry.java | 100 +
.../query/calcite/exec/MailboxRegistryImpl.java | 216 +
.../query/calcite/exec/QueryTaskExecutor.java} | 29 +-
.../query/calcite/exec/QueryTaskExecutorImpl.java | 113 +
.../processors/query/calcite/exec/RowHandler.java | 75 +
.../query/calcite/exec/RuntimeHashIndex.java | 150 +
.../query/calcite/exec/RuntimeIndex.java} | 28 +-
.../query/calcite/exec/RuntimeSortedIndex.java | 210 +
.../query/calcite/exec/SystemViewScan.java | 148 +
.../query/calcite/exec/TableFunctionScan.java | 46 +
.../processors/query/calcite/exec/TableScan.java | 282 +
.../processors/query/calcite/exec/TreeIndex.java} | 33 +-
.../query/calcite/exec/ddl/DdlCommandHandler.java | 403 +
.../calcite/exec/ddl/NativeCommandHandler.java | 51 +
.../query/calcite/exec/ddl/SchemaManager.java | 85 +
.../query/calcite/exec/exp/BiScalar.java | 27 +
.../query/calcite/exec/exp/CallImplementor.java | 42 +
.../query/calcite/exec/exp/ConverterUtils.java | 458 +
.../query/calcite/exec/exp/ExpressionFactory.java | 113 +
.../calcite/exec/exp/ExpressionFactoryImpl.java | 687 +
.../calcite/exec/exp/IgniteScalarFunction.java | 67 +
.../query/calcite/exec/exp/IgniteSqlFunctions.java | 255 +
.../calcite/exec/exp/ImplementableFunction.java | 36 +
.../query/calcite/exec/exp/NotNullImplementor.java | 43 +
.../exec/exp/ReflectiveCallNotNullImplementor.java | 82 +
.../query/calcite/exec/exp/RexExecutorImpl.java | 193 +
.../query/calcite/exec/exp/RexImpTable.java | 2576 ++
.../query/calcite/exec/exp/RexToLixTranslator.java | 1374 +
.../processors/query/calcite/exec/exp/Scalar.java | 22 +
.../query/calcite/exec/exp/SingleScalar.java} | 31 +-
.../exec/exp/TableFunctionCallImplementor.java | 44 +
.../query/calcite/exec/exp/agg/Accumulator.java} | 44 +-
.../calcite/exec/exp/agg/AccumulatorWrapper.java} | 31 +-
.../query/calcite/exec/exp/agg/Accumulators.java | 1020 +
.../calcite/exec/exp/agg/AccumulatorsFactory.java | 334 +
.../query/calcite/exec/exp/agg/AggregateType.java} | 30 +-
.../query/calcite/exec/exp/agg/GroupKey.java | 100 +
.../query/calcite/exec/rel/AbstractNode.java | 205 +
.../query/calcite/exec/rel/AbstractSetOpNode.java | 366 +
.../exec/rel/CorrelatedNestedLoopJoinNode.java | 496 +
.../query/calcite/exec/rel/Downstream.java} | 36 +-
.../query/calcite/exec/rel/FilterNode.java | 144 +
.../query/calcite/exec/rel/HashAggregateNode.java | 383 +
.../processors/query/calcite/exec/rel/Inbox.java | 536 +
.../query/calcite/exec/rel/IndexSpoolNode.java | 206 +
.../query/calcite/exec/rel/IntersectNode.java | 118 +
.../query/calcite/exec/rel/LimitNode.java | 135 +
.../query/calcite/exec/rel/Mailbox.java} | 38 +-
.../query/calcite/exec/rel/MergeJoinNode.java | 1138 +
.../query/calcite/exec/rel/MinusNode.java | 102 +
.../query/calcite/exec/rel/ModifyNode.java | 327 +
.../query/calcite/exec/rel/NestedLoopJoinNode.java | 823 +
.../processors/query/calcite/exec/rel/Node.java | 81 +
.../processors/query/calcite/exec/rel/Outbox.java | 373 +
.../query/calcite/exec/rel/ProjectNode.java | 82 +
.../query/calcite/exec/rel/RootNode.java | 269 +
.../query/calcite/exec/rel/ScanNode.java | 144 +
.../query/calcite/exec/rel/SingleNode.java} | 32 +-
.../query/calcite/exec/rel/SortAggregateNode.java | 313 +
.../query/calcite/exec/rel/SortNode.java | 147 +
.../query/calcite/exec/rel/TableSpoolNode.java | 158 +
.../query/calcite/exec/rel/UnionAllNode.java | 96 +
.../query/calcite/externalize/RelInputEx.java | 29 +
.../query/calcite/externalize/RelJson.java | 949 +
.../query/calcite/externalize/RelJsonReader.java | 334 +
.../query/calcite/externalize/RelJsonWriter.java | 172 +
.../query/calcite/message/CalciteMessage.java} | 34 +-
.../calcite/message/CalciteMessageFactory.java} | 36 +-
.../query/calcite/message/ErrorMessage.java} | 114 +-
.../calcite/message/ExecutionContextAware.java} | 29 +-
.../query/calcite/message/GenericValueMessage.java | 117 +
.../query/calcite/message/InboxCloseMessage.java | 153 +
.../query/calcite/message/MarshalableMessage.java} | 31 +-
.../query/calcite/message/MarshallingContext.java | 58 +
.../query/calcite/message/MessageListener.java} | 27 +-
.../query/calcite/message/MessageService.java} | 40 +-
.../query/calcite/message/MessageServiceImpl.java | 282 +
.../query/calcite/message/MessageType.java | 89 +
.../message/QueryBatchAcknowledgeMessage.java | 174 +
.../query/calcite/message/QueryBatchMessage.java | 267 +
.../query/calcite/message/QueryCloseMessage.java | 101 +
.../query/calcite/message/QueryStartRequest.java | 296 +
.../query/calcite/message/QueryStartResponse.java} | 126 +-
.../query/calcite/message/ValueMessage.java} | 36 +-
.../query/calcite/metadata/AffinityService.java} | 28 +-
.../calcite/metadata/AffinityServiceImpl.java | 63 +
.../query/calcite/metadata/ColocationGroup.java | 532 +
.../metadata/ColocationMappingException.java} | 26 +-
.../calcite/metadata/FragmentDescription.java | 221 +
.../query/calcite/metadata/FragmentMapping.java | 217 +
.../calcite/metadata/FragmentMappingException.java | 58 +
.../query/calcite/metadata/IgniteMdCollation.java | 408 +
.../calcite/metadata/IgniteMdColumnOrigins.java | 386 +
.../calcite/metadata/IgniteMdCumulativeCost.java | 113 +
.../calcite/metadata/IgniteMdDistinctRowCount.java | 53 +
.../calcite/metadata/IgniteMdDistribution.java | 111 +
.../calcite/metadata/IgniteMdFragmentMapping.java | 226 +
.../metadata/IgniteMdNonCumulativeCost.java | 46 +
.../metadata/IgniteMdPercentageOriginalRows.java | 161 +
.../query/calcite/metadata/IgniteMdPredicates.java | 50 +
.../query/calcite/metadata/IgniteMdRowCount.java | 146 +
.../calcite/metadata/IgniteMdSelectivity.java | 676 +
.../query/calcite/metadata/IgniteMetadata.java | 73 +
.../query/calcite/metadata/MappingService.java | 43 +
.../query/calcite/metadata/MappingServiceImpl.java | 78 +
.../calcite/metadata/NodeMappingException.java} | 36 +-
.../query/calcite/metadata/RelMetadataQueryEx.java | 104 +
.../query/calcite/metadata/RemoteException.java} | 49 +-
.../query/calcite/metadata/cost/IgniteCost.java | 232 +
.../calcite/metadata/cost/IgniteCostFactory.java | 101 +
.../calcite/prepare/AbstractMultiStepPlan.java | 105 +
.../calcite/prepare/AbstractQueryContext.java} | 33 +-
.../query/calcite/prepare/BaseDataContext.java | 90 +
.../query/calcite/prepare/BaseQueryContext.java | 322 +
.../processors/query/calcite/prepare/CacheKey.java | 78 +
.../calcite/prepare/CalciteQueryFieldMetadata.java | 129 +
.../processors/query/calcite/prepare/Cloner.java | 249 +
.../processors/query/calcite/prepare/DdlPlan.java} | 42 +-
.../query/calcite/prepare/ExecutionPlan.java} | 41 +-
.../query/calcite/prepare/ExplainPlan.java} | 53 +-
.../query/calcite/prepare/FieldsMetadata.java | 75 +
.../query/calcite/prepare/FieldsMetadataImpl.java} | 42 +-
.../processors/query/calcite/prepare/Fragment.java | 181 +
.../query/calcite/prepare/FragmentPlan.java} | 47 +-
.../query/calcite/prepare/FragmentSplitter.java | 143 +
.../query/calcite/prepare/IdGenerator.java} | 30 +-
.../calcite/prepare/IgniteConvertletTable.java | 133 +
.../query/calcite/prepare/IgnitePlanner.java | 539 +
.../query/calcite/prepare/IgnitePrograms.java | 77 +
.../query/calcite/prepare/IgniteRelShuttle.java | 215 +
.../calcite/prepare/IgniteSqlToRelConvertor.java | 168 +
.../query/calcite/prepare/IgniteSqlValidator.java | 483 +
.../query/calcite/prepare/IgniteTypeCoercion.java | 120 +
.../query/calcite/prepare/MappingQueryContext.java | 68 +
.../query/calcite/prepare/MultiStepDmlPlan.java} | 36 +-
.../query/calcite/prepare/MultiStepPlan.java | 59 +
.../query/calcite/prepare/MultiStepQueryPlan.java} | 36 +-
.../query/calcite/prepare/PlannerHelper.java | 236 +
.../query/calcite/prepare/PlannerPhase.java | 278 +
.../query/calcite/prepare/PlanningContext.java | 277 +
.../query/calcite/prepare/PrepareService.java} | 27 +-
.../query/calcite/prepare/PrepareServiceImpl.java | 199 +
.../query/calcite/prepare/QueryPlan.java} | 30 +-
.../query/calcite/prepare/QueryPlanCache.java} | 36 +-
.../query/calcite/prepare/QueryPlanCacheImpl.java | 157 +
.../query/calcite/prepare/QueryTemplate.java | 139 +
.../processors/query/calcite/prepare/Splitter.java | 124 +
.../query/calcite/prepare/ValidationResult.java | 70 +
.../prepare/ddl/AbstractAlterTableCommand.java | 74 +
.../calcite/prepare/ddl/AlterTableAddCommand.java | 61 +
.../calcite/prepare/ddl/AlterTableDropCommand.java | 61 +
.../calcite/prepare/ddl/ColumnDefinition.java | 83 +
.../calcite/prepare/ddl/CreateTableCommand.java | 321 +
.../query/calcite/prepare/ddl/DdlCommand.java} | 29 +-
.../prepare/ddl/DdlSqlToCommandConverter.java | 473 +
.../calcite/prepare/ddl/DropTableCommand.java | 74 +
.../calcite/prepare/ddl/NativeCommandWrapper.java} | 33 +-
.../prepare/ddl/SqlToNativeCommandConverter.java | 229 +
.../calcite/prepare/ddl/TransactionCommand.java} | 27 +-
.../query/calcite/rel/AbstractIgniteJoin.java | 317 +
.../query/calcite/rel/AbstractIndexScan.java | 166 +
.../query/calcite/rel/IgniteAggregate.java | 120 +
.../query/calcite/rel/IgniteConvention.java} | 46 +-
.../rel/IgniteCorrelatedNestedLoopJoin.java | 246 +
.../query/calcite/rel/IgniteExchange.java | 98 +
.../processors/query/calcite/rel/IgniteFilter.java | 139 +
.../query/calcite/rel/IgniteHashIndexSpool.java | 144 +
.../query/calcite/rel/IgniteIndexScan.java | 149 +
.../processors/query/calcite/rel/IgniteLimit.java | 198 +
.../query/calcite/rel/IgniteMergeJoin.java | 321 +
.../query/calcite/rel/IgniteNestedLoopJoin.java | 115 +
.../query/calcite/rel/IgniteProject.java | 222 +
.../query/calcite/rel/IgniteReceiver.java | 145 +
.../processors/query/calcite/rel/IgniteRel.java | 89 +
.../query/calcite/rel/IgniteRelVisitor.java | 173 +
.../processors/query/calcite/rel/IgniteSender.java | 146 +
.../processors/query/calcite/rel/IgniteSort.java | 132 +
.../query/calcite/rel/IgniteSortedIndexSpool.java | 152 +
.../query/calcite/rel/IgniteTableFunctionScan.java | 87 +
.../query/calcite/rel/IgniteTableModify.java | 105 +
.../query/calcite/rel/IgniteTableScan.java | 136 +
.../query/calcite/rel/IgniteTableSpool.java | 91 +
.../query/calcite/rel/IgniteTrimExchange.java | 119 +
.../query/calcite/rel/IgniteUnionAll.java | 146 +
.../processors/query/calcite/rel/IgniteValues.java | 74 +
.../rel/ProjectableFilterableTableScan.java | 194 +
.../query/calcite/rel/SourceAwareIgniteRel.java} | 29 +-
.../rel/agg/IgniteColocatedAggregateBase.java | 109 +
.../rel/agg/IgniteColocatedHashAggregate.java | 71 +
.../rel/agg/IgniteColocatedSortAggregate.java | 106 +
.../calcite/rel/agg/IgniteHashAggregateBase.java | 46 +
.../calcite/rel/agg/IgniteMapAggregateBase.java | 94 +
.../calcite/rel/agg/IgniteMapHashAggregate.java | 103 +
.../calcite/rel/agg/IgniteMapSortAggregate.java | 140 +
.../calcite/rel/agg/IgniteReduceAggregateBase.java | 174 +
.../calcite/rel/agg/IgniteReduceHashAggregate.java | 116 +
.../calcite/rel/agg/IgniteReduceSortAggregate.java | 126 +
.../calcite/rel/agg/IgniteSortAggregateBase.java | 90 +
.../rel/logical/IgniteLogicalIndexScan.java | 84 +
.../rel/logical/IgniteLogicalTableScan.java | 64 +
.../calcite/rel/set/IgniteColocatedIntersect.java | 67 +
.../calcite/rel/set/IgniteColocatedMinus.java | 67 +
.../calcite/rel/set/IgniteColocatedSetOp.java | 128 +
.../query/calcite/rel/set/IgniteIntersect.java | 67 +
.../query/calcite/rel/set/IgniteMapIntersect.java | 73 +
.../query/calcite/rel/set/IgniteMapMinus.java | 73 +
.../query/calcite/rel/set/IgniteMapSetOp.java | 107 +
.../query/calcite/rel/set/IgniteMinus.java | 70 +
.../calcite/rel/set/IgniteReduceIntersect.java | 89 +
.../query/calcite/rel/set/IgniteReduceMinus.java | 89 +
.../query/calcite/rel/set/IgniteReduceSetOp.java | 74 +
.../query/calcite/rel/set/IgniteSetOp.java | 77 +
.../calcite/rule/AbstractIgniteConverterRule.java | 55 +
.../calcite/rule/CorrelateToNestedLoopRule.java | 90 +
.../calcite/rule/CorrelatedNestedLoopJoinRule.java | 149 +
.../query/calcite/rule/FilterConverterRule.java | 71 +
.../rule/FilterSpoolMergeToHashIndexSpoolRule.java | 114 +
.../FilterSpoolMergeToSortedIndexSpoolRule.java | 164 +
.../calcite/rule/HashAggregateConverterRule.java | 117 +
.../calcite/rule/LogicalScanConverterRule.java | 198 +
.../query/calcite/rule/MergeJoinConverterRule.java | 73 +
.../calcite/rule/NestedLoopJoinConverterRule.java | 56 +
.../query/calcite/rule/ProjectConverterRule.java | 69 +
.../query/calcite/rule/SetOpConverterRule.java | 185 +
.../calcite/rule/SortAggregateConverterRule.java | 142 +
.../query/calcite/rule/SortConverterRule.java | 81 +
.../rule/TableFunctionScanConverterRule.java | 63 +
.../calcite/rule/TableModifyConverterRule.java | 60 +
.../query/calcite/rule/UnionConverterRule.java | 94 +
.../query/calcite/rule/ValuesConverterRule.java | 56 +
.../calcite/rule/logical/ExposeIndexRule.java | 103 +
.../calcite/rule/logical/FilterScanMergeRule.java | 184 +
.../calcite/rule/logical/LogicalOrToUnionRule.java | 206 +
.../calcite/rule/logical/ProjectScanMergeRule.java | 257 +
.../calcite/rule/logical/RuleFactoryConfig.java | 39 +
.../query/calcite/rule/package-info.java} | 27 +-
.../calcite/schema/CacheColumnDescriptor.java | 52 +
.../query/calcite/schema/CacheIndexImpl.java | 137 +
.../query/calcite/schema/CacheTableDescriptor.java | 69 +
.../calcite/schema/CacheTableDescriptorImpl.java | 797 +
.../query/calcite/schema/CacheTableImpl.java | 192 +
.../query/calcite/schema/ColumnDescriptor.java} | 39 +-
.../query/calcite/schema/IgniteCacheTable.java} | 30 +-
.../query/calcite/schema/IgniteIndex.java | 89 +
.../query/calcite/schema/IgniteSchema.java | 91 +
.../query/calcite/schema/IgniteStatisticsImpl.java | 139 +
.../query/calcite/schema/IgniteTable.java | 158 +
.../query/calcite/schema/ModifyTuple.java} | 55 +-
.../query/calcite/schema/SchemaHolder.java} | 26 +-
.../query/calcite/schema/SchemaHolderImpl.java | 324 +
.../schema/SystemViewColumnDescriptor.java} | 30 +-
.../query/calcite/schema/SystemViewIndexImpl.java | 115 +
.../schema/SystemViewTableDescriptorImpl.java | 277 +
.../query/calcite/schema/SystemViewTableImpl.java | 178 +
.../query/calcite/schema/TableDescriptor.java | 118 +
.../calcite/sql/IgniteAbstractSqlAlterTable.java | 84 +
.../query/calcite/sql/IgniteSqlAlterTable.java | 55 +
.../calcite/sql/IgniteSqlAlterTableAddColumn.java | 75 +
.../calcite/sql/IgniteSqlAlterTableDropColumn.java | 75 +
.../query/calcite/sql/IgniteSqlAlterUser.java | 82 +
.../query/calcite/sql/IgniteSqlCommit.java | 51 +
.../query/calcite/sql/IgniteSqlConformance.java | 38 +
.../query/calcite/sql/IgniteSqlCreateIndex.java | 162 +
.../query/calcite/sql/IgniteSqlCreateTable.java | 134 +
.../calcite/sql/IgniteSqlCreateTableOption.java | 113 +
.../sql/IgniteSqlCreateTableOptionEnum.java | 55 +
.../query/calcite/sql/IgniteSqlCreateUser.java | 82 +
.../query/calcite/sql/IgniteSqlDropIndex.java | 76 +
.../query/calcite/sql/IgniteSqlDropUser.java | 66 +
.../calcite/sql/IgniteSqlIntervalTypeNameSpec.java | 62 +
.../query/calcite/sql/IgniteSqlKill.java | 110 +
.../query/calcite/sql/IgniteSqlRollback.java | 51 +
.../calcite/sql/fun/IgniteOwnSqlOperatorTable.java | 92 +
.../calcite/sql/fun/IgniteStdSqlOperatorTable.java | 291 +
.../calcite/sql/fun/SqlSystemRangeFunction.java | 60 +
.../calcite/sql/generated/IgniteSqlParserImpl.java | 33498 +++++++++++++++
.../generated/IgniteSqlParserImplConstants.java | 1584 +
.../generated/IgniteSqlParserImplTokenManager.java | 26455 ++++++++++++
.../calcite/sql/generated/ParseException.java | 192 +
.../calcite/sql/generated/SimpleCharStream.java | 439 +
.../query/calcite/sql/generated/Token.java | 81 +
.../query/calcite/sql/generated/TokenMgrError.java | 133 +
.../query/calcite/sql/generated/package-info.java | 28 +
.../calcite/sql/kill/IgniteSqlKillComputeTask.java | 68 +
.../sql/kill/IgniteSqlKillContinuousQuery.java | 82 +
.../query/calcite/sql/kill/IgniteSqlKillQuery.java | 98 +
.../calcite/sql/kill/IgniteSqlKillScanQuery.java | 95 +
.../calcite/sql/kill/IgniteSqlKillService.java | 68 +
.../calcite/sql/kill/IgniteSqlKillTransaction.java | 68 +
.../query/calcite/trait/AffinityAdapter.java | 49 +
.../processors/query/calcite/trait/AllNodes.java} | 38 +-
.../query/calcite/trait/CorrelationTrait.java | 122 +
.../query/calcite/trait/CorrelationTraitDef.java | 53 +
.../query/calcite/trait/Destination.java} | 31 +-
.../query/calcite/trait/DistributionFunction.java | 319 +
.../query/calcite/trait/DistributionTrait.java | 185 +
.../query/calcite/trait/DistributionTraitDef.java | 55 +
.../query/calcite/trait/IgniteDistribution.java | 51 +
.../query/calcite/trait/IgniteDistributions.java | 122 +
.../query/calcite/trait/Partitioned.java} | 60 +-
.../query/calcite/trait/RandomNode.java} | 51 +-
.../query/calcite/trait/RelFactory.java} | 31 +-
.../query/calcite/trait/RewindabilityTrait.java | 102 +
.../query/calcite/trait/RewindabilityTraitDef.java | 53 +
.../processors/query/calcite/trait/TraitUtils.java | 561 +
.../query/calcite/trait/TraitsAwareIgniteRel.java | 156 +
.../query/calcite/type/IgniteTypeFactory.java | 309 +
.../query/calcite/type/IgniteTypeSystem.java | 104 +
.../processors/query/calcite/type/UuidType.java} | 49 +-
.../query/calcite/util/AbstractService.java} | 38 +-
.../processors/query/calcite/util/Commons.java | 447 +
.../calcite/util/ConvertingClosableIterator.java | 72 +
.../processors/query/calcite/util/HintUtils.java | 60 +
.../query/calcite/util/IgniteMethod.java | 101 +
.../query/calcite/util/IgniteResource.java | 67 +
.../query/calcite/util/IndexConditions.java | 142 +
.../query/calcite/util/LifecycleAware.java} | 31 +-
.../query/calcite/util/ListFieldsQueryCursor.java | 115 +
.../processors/query/calcite/util/PlanUtils.java | 72 +
.../processors/query/calcite/util/RexUtils.java | 566 +
.../processors/query/calcite/util/Service.java} | 31 +-
.../processors/query/calcite/util/TypeUtils.java | 398 +
.../query/calcite/CalciteQueryProcessorTest.java | 1329 +
.../processors/query/calcite/CancelTest.java | 258 +
.../processors/query/calcite/DataTypesTest.java | 348 +
.../processors/query/calcite/DateTimeTest.java | 268 +
.../processors/query/calcite/FunctionsTest.java | 317 +
.../processors/query/calcite/LimitOffsetTest.java | 349 +
.../processors/query/calcite/QueryChecker.java | 490 +
.../processors/query/calcite/QueryCheckerTest.java | 61 +
.../query/calcite/SqlFieldsQueryUsageTest.java | 107 +
.../query/calcite/StdSqlOperatorsTest.java | 335 +
.../processors/query/calcite/TestUtils.java} | 33 +-
.../query/calcite/UnstableTopologyTest.java | 206 +
.../calcite/exec/ClosableIteratorsHolderTest.java | 109 +
.../calcite/exec/LogicalRelImplementorTest.java | 329 +
.../query/calcite/exec/RuntimeSortedIndexTest.java | 196 +
.../calcite/exec/exp/IgniteSqlFunctionsTest.java | 139 +
.../calcite/exec/rel/AbstractExecutionTest.java | 465 +
.../exec/rel/AbstractSetOpExecutionTest.java | 195 +
.../query/calcite/exec/rel/BaseAggregateTest.java | 692 +
.../calcite/exec/rel/ContinuousExecutionTest.java | 184 +
.../query/calcite/exec/rel/ExecutionTest.java | 693 +
.../exec/rel/HashAggregateExecutionTest.java | 208 +
.../rel/HashAggregateSingleGroupExecutionTest.java | 530 +
.../exec/rel/HashIndexSpoolExecutionTest.java | 205 +
.../calcite/exec/rel/IntersectExecutionTest.java | 82 +
.../query/calcite/exec/rel/LimitExecutionTest.java | 113 +
.../calcite/exec/rel/MergeJoinExecutionTest.java | 452 +
.../query/calcite/exec/rel/MinusExecutionTest.java | 82 +
.../exec/rel/NestedLoopJoinExecutionTest.java | 380 +
.../exec/rel/SortAggregateExecutionTest.java | 146 +
.../exec/rel/SortedIndexSpoolExecutionTest.java | 242 +
.../calcite/exec/rel/TableSpoolExecutionTest.java | 170 +
.../integration/AbstractBasicIntegrationTest.java | 258 +
.../integration/AbstractDdlIntegrationTest.java | 73 +
.../integration/AggregatesIntegrationTest.java | 197 +
.../CalciteBasicSecondaryIndexIntegrationTest.java | 1183 +
.../CalciteErrorHandlilngIntegrationTest.java | 242 +
.../integration/CorrelatesIntegrationTest.java | 79 +
.../integration/HashSpoolIntegrationTest.java | 83 +
.../integration/IndexDdlIntegrationTest.java | 200 +
.../integration/IndexRebuildIntegrationTest.java | 316 +
.../integration/IndexScanlIntegrationTest.java | 92 +
.../integration/IndexSpoolIntegrationTest.java | 179 +
.../query/calcite/integration/IntervalTest.java | 379 +
.../calcite/integration/JoinIntegrationTest.java | 863 +
.../integration/KillCommandDdlIntegrationTest.java | 315 +
.../KillQueryCommandDdlIntegrationTest.java | 165 +
.../integration/MetadataIntegrationTest.java | 75 +
.../QueryEngineConfigurationIntegrationTest.java | 251 +
.../integration/RunningQueriesIntegrationTest.java | 333 +
.../ServerStatisticsIntegrationTest.java | 616 +
.../calcite/integration/SetOpIntegrationTest.java | 469 +
.../integration/SortAggregateIntegrationTest.java | 176 +
.../integration/SystemViewsIntegrationTest.java | 149 +
.../integration/TableDdlIntegrationTest.java | 792 +
.../integration/TableDmlIntegrationTest.java | 545 +
.../integration/UserDdlIntegrationTest.java | 98 +
.../UserDefinedFunctionsIntegrationTest.java | 169 +
.../query/calcite/jdbc/JdbcCrossEngineTest.java | 208 +
.../query/calcite/jdbc/JdbcQueryTest.java | 198 +
.../logical/ScriptRunnerTestsEnvironment.java | 58 +
.../query/calcite/logical/ScriptTestRunner.java | 271 +
.../query/calcite/logical/SqlScriptRunner.java | 759 +
.../query/calcite/message/TestIoManager.java} | 34 +-
.../planner/AbstractAggregatePlannerTest.java | 87 +
.../query/calcite/planner/AbstractPlannerTest.java | 878 +
.../planner/AggregateDistinctPlannerTest.java | 147 +
.../calcite/planner/AggregatePlannerTest.java | 462 +
.../CorrelatedNestedLoopJoinPlannerTest.java | 170 +
.../planner/CorrelatedSubqueryPlannerTest.java | 267 +
.../calcite/planner/HashAggregatePlannerTest.java | 140 +
.../calcite/planner/HashIndexSpoolPlannerTest.java | 230 +
.../calcite/planner/IndexRebuildPlannerTest.java | 93 +
.../calcite/planner/JoinColocationPlannerTest.java | 201 +
.../calcite/planner/JoinCommutePlannerTest.java | 214 +
.../calcite/planner/JoinWithUsingPlannerTest.java | 185 +
.../calcite/planner/LimitOffsetPlannerTest.java | 189 +
.../calcite/planner/MergeJoinPlannerTest.java | 2799 ++
.../query/calcite/planner/PlannerTest.java | 1302 +
.../query/calcite/planner/PlannerTimeoutTest.java | 114 +
.../planner/ProjectFilterScanMergePlannerTest.java | 247 +
.../query/calcite/planner/SetOpPlannerTest.java | 496 +
.../calcite/planner/SortAggregatePlannerTest.java | 284 +
.../planner/SortedIndexSpoolPlannerTest.java | 272 +
.../calcite/planner/StatisticsPlannerTest.java | 457 +
.../query/calcite/planner/TableDmlPlannerTest.java | 172 +
.../calcite/planner/TableFunctionPlannerTest.java | 110 +
.../calcite/planner/TableSpoolPlannerTest.java | 86 +
.../query/calcite/planner/TestTable.java | 259 +
.../query/calcite/planner/UnionPlannerTest.java | 163 +
.../query/calcite/rules/JoinCommuteRulesTest.java | 112 +
.../query/calcite/rules/OrToUnionRuleTest.java | 313 +
.../calcite/rules/ProjectScanMergeRuleTest.java | 173 +
.../query/calcite/sql/SqlCustomParserTest.java | 908 +
.../ignite/testsuites/ExecutionTestSuite.java | 58 +
.../ignite/testsuites/IgniteCalciteTestSuite.java | 46 +
.../ignite/testsuites/IntegrationTestSuite.java | 106 +
.../apache/ignite/testsuites/PlannerTestSuite.java | 76 +
.../apache/ignite/testsuites/ScriptTestSuite.java | 77 +
.../sql/aggregate/aggregates/test_aggr_string.test | 82 +
.../aggregate/aggregates/test_aggregate_types.test | 176 +
.../aggregates/test_aggregate_types.test_ignore | 191 +
.../aggregates/test_aggregate_types_scalar.test | 93 +
.../test_aggregate_types_scalar.test_ignored | 111 +
.../aggregates/test_approx_quantile.test_ignore | 170 +
.../test_approximate_distinct_count.test_ignore | 93 +
.../aggregates/test_arg_min_max.test_ignore | 131 +
.../test/sql/aggregate/aggregates/test_avg.test | 40 +
.../sql/aggregate/aggregates/test_avg.test_ignored | 54 +
.../aggregate/aggregates/test_bit_and.test_ignore | 57 +
.../aggregate/aggregates/test_bit_or.test_ignore | 57 +
.../aggregate/aggregates/test_bit_xor.test_ignore | 57 +
.../test/sql/aggregate/aggregates/test_count.test | 51 +
.../sql/aggregate/aggregates/test_count_star.test | 46 +
.../aggregate/aggregates/test_covar.test_ignore | 100 +
.../aggregate/aggregates/test_distinct_aggr.test | 21 +
.../test_distinct_string_agg.test_ignore | 17 +
.../aggregate/aggregates/test_empty_aggregate.test | 29 +
.../aggregates/test_empty_aggregate.test_ignore | 31 +
.../aggregates/test_group_by_many_groups.test_slow | 14 +
.../aggregates/test_group_on_expression.test | 75 +
.../aggregates/test_histogram.test_ignore | 94 +
.../sql/aggregate/aggregates/test_mode.test_ignore | 97 +
.../aggregate/aggregates/test_null_aggregates.test | 406 +
.../sql/aggregate/aggregates/test_perfect_ht.test | 168 +
.../aggregates/test_perfect_ht.test_ignore | 177 +
.../aggregate/aggregates/test_quantile.test_ignore | 222 +
.../aggregates/test_quantile_list.test_ignore | 115 +
.../aggregates/test_regression.test_ignore | 347 +
.../sql/aggregate/aggregates/test_scalar_aggr.test | 54 +
.../aggregates/test_scalar_aggr.test_ignore | 58 +
.../aggregate/aggregates/test_stddev.test_ignore | 123 +
.../aggregates/test_string_agg.test_ignore | 91 +
.../aggregates/test_string_agg_big.test_ignore | 17 +
.../test_string_agg_many_groups.test_slow_ignore | 23 +
.../test/sql/aggregate/aggregates/test_sum.test | 81 +
.../test/sql/aggregate/distinct/test_distinct.test | 55 +
.../distinct/test_distinct_on.test_ignore | 133 +
.../aggregate/distinct/test_distinct_order_by.test | 41 +
.../test/sql/aggregate/group/test_group_by.test | 160 +
.../sql/aggregate/group/test_group_by.test_ignore | 182 +
.../sql/aggregate/group/test_group_by_alias.test | 38 +
.../group/test_group_by_alias.test_ignore | 68 +
.../group/test_group_by_large_string.test | 16 +
.../group/test_group_by_multi_column.test | 17 +
.../test/sql/aggregate/group/test_group_null.test | 17 +
.../test_corel_subquery_in_having.test_ignore | 38 +
.../src/test/sql/aggregate/having/test_having.test | 45 +
.../having/test_scalar_having.test_ignore | 119 +
.../src/test/sql/cast/test_boolean_cast.test | 130 +
.../test/sql/cast/test_boolean_cast.test_ignore | 160 +
.../sql/cast/test_exponent_in_cast.test_ignore | 45 +
.../src/test/sql/cast/test_string_cast.test | 55 +
.../calcite/src/test/sql/cast/test_try_cast.test | 22 +
.../calcite/src/test/sql/delete/test_delete.test | 33 +
.../src/test/sql/delete/test_large_delete.test | 15 +
.../src/test/sql/filter/test_alias_filter.test | 20 +
.../test/sql/filter/test_constant_comparisons.test | 103 +
.../filter/test_constant_comparisons.test_ignore | 12 +
.../src/test/sql/filter/test_filter_clause.test | 460 +
.../test/sql/filter/test_filter_clause.test_ignore | 528 +
.../src/test/sql/filter/test_illegal_filters.test | 17 +
.../src/test/sql/filter/test_obsolete_filters.test | 271 +
.../sql/filter/test_obsolete_filters.test_ignore | 281 +
.../test/sql/filter/test_transitive_filters.test | 321 +
.../calcite/src/test/sql/filter/test_zonemap.test | 34 +
.../calcite/src/test/sql/function/blob/base64.test | 27 +
.../src/test/sql/function/date/date_part.test | 189 +
.../test/sql/function/date/date_part.test_ignore | 214 +
.../src/test/sql/function/date/test_date_part.test | 61 +
.../sql/function/date/test_date_part.test_ignore | 166 +
.../src/test/sql/function/date/test_extract.test | 111 +
.../sql/function/date/test_extract.test_ignore | 112 +
.../sql/function/date/test_extract_edge_cases.test | 67 +
.../date/test_extract_edge_cases.test_ignore | 342 +
.../test/sql/function/date/test_extract_month.test | 748 +
.../test/sql/function/date/test_extract_year.test | 653 +
.../test/sql/function/generic/test_between.test | 219 +
.../src/test/sql/function/generic/test_case.test | 93 +
.../test/sql/function/generic/test_coalesce.test | 52 +
.../sql/function/generic/test_coalesce.test_ignore | 15 +
.../src/test/sql/function/generic/test_decode.test | 24 +
.../sql/function/generic/test_decode.test_ignore | 20 +
.../src/test/sql/function/generic/test_in.test | 135 +
.../sql/function/generic/test_large_in.test_ignore | 49 +
.../sql/function/generic/test_least_greatest.test | 118 +
.../test/sql/function/generic/test_null_if.test | 54 +
.../src/test/sql/function/generic/test_nvl.test | 29 +
.../test/sql/function/interval/test_extract.test | 233 +
.../src/test/sql/function/json/test_json.test | 28 +
.../test/sql/function/numeric/test_floor_ceil.test | 140 +
.../sql/function/numeric/test_invalid_math.test | 37 +
.../src/test/sql/function/numeric/test_mod.test | 25 +
.../sql/function/numeric/test_oracle_math.test | 20 +
.../test/sql/function/numeric/test_pg_math.test | 86 +
.../src/test/sql/function/numeric/test_pow.test | 35 +
.../src/test/sql/function/numeric/test_random.test | 31 +
.../src/test/sql/function/numeric/test_round.test | 55 +
.../src/test/sql/function/numeric/test_trigo.test | 445 +
.../test/sql/function/numeric/test_truncate.test | 44 +
.../sql/function/numeric/test_type_resolution.test | 202 +
.../src/test/sql/function/numeric/test_unary.test | 61 +
.../sql/function/operator/test_arithmetic.test | 143 +
.../operator/test_arithmetic_sqllogic.test | 51 +
.../sql/function/operator/test_comparison.test | 42 +
.../sql/function/operator/test_conjunction.test | 189 +
.../calcite/src/test/sql/function/string/md5.test | 37 +
.../sql/function/string/regex_filter_pushdown.test | 31 +
.../sql/function/string/regex_replace.test_ignore | 77 +
.../src/test/sql/function/string/regex_search.test | 129 +
.../sql/function/string/regex_search.test_ignore | 143 +
.../calcite/src/test/sql/function/string/sha1.test | 9 +
.../src/test/sql/function/string/test_ascii.test | 78 +
.../test/sql/function/string/test_caseconvert.test | 69 +
.../test/sql/function/string/test_char_length.test | 36 +
.../function/string/test_char_length.test_ignore | 9 +
.../string/test_complex_unicode.test_ignore | 83 +
.../test/sql/function/string/test_compress.test | 10 +
.../src/test/sql/function/string/test_concat.test | 75 +
.../sql/function/string/test_concat_function.test | 62 +
.../test/sql/function/string/test_difference.test | 40 +
.../src/test/sql/function/string/test_initcap.test | 29 +
.../src/test/sql/function/string/test_left.test | 80 +
.../test/sql/function/string/test_left.test_ignore | 102 +
.../src/test/sql/function/string/test_length.test | 26 +
.../sql/function/string/test_length.test_ignore | 27 +
.../src/test/sql/function/string/test_like.test | 285 +
.../test/sql/function/string/test_like_escape.test | 100 +
.../function/string/test_like_escape.test_ignore | 106 +
.../src/test/sql/function/string/test_overlay.test | 19 +
.../test/sql/function/string/test_position.test | 58 +
.../src/test/sql/function/string/test_repeat.test | 58 +
.../src/test/sql/function/string/test_replace.test | 76 +
.../src/test/sql/function/string/test_reverse.test | 49 +
.../src/test/sql/function/string/test_right.test | 63 +
.../sql/function/string/test_right.test_ignore | 84 +
.../test/sql/function/string/test_similar_to.test | 137 +
.../src/test/sql/function/string/test_soundex.test | 28 +
.../src/test/sql/function/string/test_space.test | 9 +
.../src/test/sql/function/string/test_strcmp.test | 18 +
.../test/sql/function/string/test_substring.test | 191 +
.../string/test_substring_utf8.test_ignore | 57 +
.../test/sql/function/string/test_translate.test | 19 +
.../src/test/sql/function/string/test_trim.test | 106 +
.../src/test/sql/function/time/test_extract.test | 74 +
.../sql/function/time/test_extract.test_ignore | 102 +
.../test/sql/function/timestamp/current_time.test | 6 +
.../test/sql/function/timestamp/test_extract.test | 92 +
.../function/timestamp/test_extract.test_ignore | 100 +
.../sql/function/timestamp/test_extract_ms.test | 23 +
.../function/timestamp/test_extract_ms.test_ignore | 35 +
.../sql/function/timestamp/test_timestampadd.test | 90 +
.../sql/function/timestamp/test_timestampdiff.test | 138 +
.../timestamp/test_timestampdiff.test_ignore | 15 +
.../src/test/sql/insert/test_big_insert.test | 55 +
.../src/test/sql/insert/test_insert.test_ignore | 41 +
.../src/test/sql/insert/test_insert_invalid.test | 28 +
.../src/test/sql/insert/test_insert_query.test | 19 +
.../src/test/sql/insert/test_insert_type.test | 33 +
.../sql/join/full_outer/test_full_outer_join.test | 53 +
.../full_outer/test_full_outer_join_complex.test | 31 +
.../test_full_outer_join_inequality.test | 31 +
.../test_full_outer_join_many_matches.test | 21 +
.../full_outer/test_full_outer_join_range.test | 32 +
.../test/sql/join/inner/join_cross_product.test | 39 +
.../src/test/sql/join/inner/test_eq_ineq_join.test | 131 +
.../calcite/src/test/sql/join/inner/test_join.test | 100 +
.../join/inner/test_join_duplicates.test_ignore | 27 +
.../sql/join/inner/test_join_types.test_ignore | 402 +
.../test/sql/join/inner/test_lt_join.test_ignore | 31 +
.../src/test/sql/join/inner/test_range_join.test | 59 +
.../src/test/sql/join/inner/test_unequal_join.test | 83 +
.../inner/test_unequal_join_duplicates.test_ignore | 25 +
.../src/test/sql/join/inner/test_using_chain.test | 84 +
.../src/test/sql/join/inner/test_using_join.test | 69 +
.../sql/join/inner/test_using_join.test_ignore | 87 +
.../src/test/sql/join/inner/test_varchar_join.test | 27 +
.../sql/join/left_outer/left_join_issue_1172.test | 120 +
.../test/sql/join/left_outer/test_left_outer.test | 180 +
.../sql/join/mark/test_mark_join_types.test_ignore | 678 +
.../src/test/sql/join/natural/natural_join.test | 74 +
.../test/sql/join/natural/natural_join.test_ignore | 122 +
.../sql/join/right_outer/test_right_outer.test | 153 +
.../src/test/sql/join/test_complex_join_expr.test | 37 +
.../test_cross_product_parallelism.test_ignore | 22 +
.../src/test/sql/join/test_join_on_aggregates.test | 32 +
.../src/test/sql/join/test_not_distinct_from.test | 191 +
.../sql/join/test_not_distinct_from.test_ignore | 256 +
modules/calcite/src/test/sql/order/test_limit.test | 45 +
.../src/test/sql/order/test_limit.test_ignore | 186 +
.../src/test/sql/order/test_nulls_first.ignore | 20 +
.../src/test/sql/order/test_nulls_first.test | 78 +
.../calcite/src/test/sql/order/test_order_by.test | 128 +
.../src/test/sql/order/test_order_by.test_ignore | 174 +
.../test/sql/order/test_order_by_exceptions.test | 60 +
.../src/test/sql/order/test_order_large.test | 12 +
.../src/test/sql/order/test_order_pragma.test | 28 +
.../test/sql/order/test_order_same_value.test_slow | 79 +
.../test_order_variable_size_payload.test_ignore | 408 +
modules/calcite/src/test/sql/order/test_top_n.test | 43 +
.../src/test/sql/sqlite/aggregates/agg1.test | 34403 ++++++++++++++++
.../test/sql/sqlite/aggregates/agg1.test_ignored | 34492 ++++++++++++++++
.../src/test/sql/sqlite/aggregates/agg2.test | 32481 +++++++++++++++
.../test/sql/sqlite/aggregates/agg2.test_ignored | 32616 +++++++++++++++
.../src/test/sql/sqlite/aggregates/agg3.test | 33678 +++++++++++++++
.../test/sql/sqlite/aggregates/agg3.test_ignored | 33723 +++++++++++++++
.../src/test/sql/sqlite/aggregates/agg4.test | 34042 ++++++++++++++++
.../test/sql/sqlite/aggregates/agg4.test_ignored | 34088 ++++++++++++++++
.../calcite/src/test/sql/sqlite/join/join1.test | 158 +
.../src/test/sql/sqlite/orderby/orderby1_10_1.test | 5758 +++
.../test/sql/sqlite/orderby/orderby1_10_10.test | 7805 ++++
.../src/test/sql/sqlite/orderby/orderby1_10_2.test | 5082 +++
.../sql/sqlite/orderby/orderby1_10_2_long1.test | 123 +
.../sql/sqlite/orderby/orderby1_10_2_long2.test | 133 +
.../sql/sqlite/orderby/orderby1_10_2_long3.test | 132 +
.../sql/sqlite/orderby/orderby1_10_2_long4.test | 135 +
.../sql/sqlite/orderby/orderby1_10_2_long5.test | 127 +
.../sql/sqlite/orderby/orderby1_10_2_long6.test | 125 +
.../sql/sqlite/orderby/orderby1_10_2_long7.test | 129 +
.../src/test/sql/sqlite/orderby/orderby1_10_3.test | 6208 +++
.../src/test/sql/sqlite/orderby/orderby1_10_4.test | 7477 ++++
.../src/test/sql/sqlite/orderby/orderby1_10_5.test | 5472 +++
.../src/test/sql/sqlite/orderby/orderby1_10_6.test | 6273 +++
.../src/test/sql/sqlite/orderby/orderby1_10_7.test | 4841 +++
.../src/test/sql/sqlite/orderby/orderby1_10_8.test | 5260 +++
.../src/test/sql/sqlite/orderby/orderby1_10_9.test | 6575 +++
.../test/sql/sqlite/select1/select1.test_native | 12187 ++++++
.../select1/select1_erroneous_res.test_ignored | 2684 ++
.../sql/sqlite/select1/select1_hashed_results.test | 7774 ++++
.../test/sql/sqlite/select1/select1_results.test | 1068 +
.../test/sql/sqlite/select2/select2.test_native | 11215 +++++
.../select2_erroneous_hash_res.test_ignored | 8490 ++++
.../select2/select2_erroneous_res.test_ignored | 223 +
.../sql/sqlite/select2/select2_hashed_results.test | 1085 +
.../test/sql/sqlite/select2/select2_results.test | 1487 +
.../test/sql/sqlite/select3/select3.test_native | 40766 +++++++++++++++++++
.../select3/select3_erroneous_hash_res.test_ignore | 19817 +++++++++
.../select3/select3_erroneous_res.test_ignore | 8962 ++++
.../test/sql/sqlite/select3/select3_results.test | 11906 ++++++
.../test/sql/subquery/any_all/test_any_all.test | 82 +
.../any_all/test_correlated_any_all.test_ignore | 182 +
.../any_all/test_scalar_any_all.test_ignore | 50 +
.../test/sql/subquery/any_all/test_scalar_in.test | 38 +
.../subquery/any_all/test_scalar_in.test_ignore | 77 +
.../sql/subquery/any_all/test_simple_not_in.test | 36 +
.../any_all/test_uncorrelated_all_subquery.test | 196 +
.../test_uncorrelated_all_subquery.test_ignore | 217 +
.../any_all/test_uncorrelated_any_subquery.test | 131 +
.../subquery/exists/test_correlated_exists.test | 67 +
.../exists/test_correlated_exists.test_ignore | 94 +
.../sql/subquery/exists/test_scalar_exists.test | 36 +
.../exists/test_uncorrelated_exists_subquery.test | 115 +
.../sql/subquery/lateral/test_lateral_join.test | 26 +
.../scalar/test_complex_correlated_subquery.test | 82 +
.../test_complex_correlated_subquery.test_ignore | 162 +
.../test_complex_nested_correlated_subquery.test | 27 +
..._complex_nested_correlated_subquery.test_ignore | 50 +
.../scalar/test_correlated_aggregate_subquery.test | 110 +
.../test_correlated_aggregate_subquery.test_ignore | 359 +
.../subquery/scalar/test_correlated_subquery.test | 137 +
.../scalar/test_correlated_subquery_cte.test | 123 +
.../test_correlated_subquery_cte.test_ignore | 133 +
.../scalar/test_correlated_subquery_where.test | 33 +
.../subquery/scalar/test_count_star_subquery.test | 20 +
.../scalar/test_count_star_subquery.test_ignore | 102 +
.../sql/subquery/scalar/test_delete_subquery.test | 34 +
.../scalar/test_grouped_correlated_subquery.test | 38 +
.../test_grouped_correlated_subquery.test_ignore | 137 +
.../sql/subquery/scalar/test_join_in_subquery.test | 34 +
.../test_many_correlated_columns.test_ignore | 65 +
.../test_nested_correlated_subquery.test_ignore | 329 +
.../sql/subquery/scalar/test_scalar_subquery.test | 134 +
.../subquery/scalar/test_scalar_subquery_cte.test | 141 +
.../scalar/test_tpcds_correlated_subquery.test | 11 +
.../test_tpcds_correlated_subquery.test_ignore | 16 +
.../scalar/test_uncorrelated_scalar_subquery.test | 41 +
.../test_uncorrelated_scalar_subquery.test_ignore | 128 +
.../scalar/test_uncorrelated_varchar_subquery.test | 67 +
.../sql/subquery/scalar/test_update_subquery.test | 61 +
.../scalar/test_update_subquery.test_ignore | 73 +
.../test_varchar_correlated_subquery.test_ignore | 93 +
.../test_window_function_subquery.test_ignore | 79 +
.../sql/subquery/table/test_aliasing.test_ignore | 24 +
.../subquery/table/test_nested_table_subquery.test | 27 +
.../sql/subquery/table/test_subquery_union.test | 13 +
.../sql/subquery/table/test_table_subquery.test | 44 +
.../subquery/table/test_table_subquery.test_ignore | 55 +
.../src/test/sql/subquery/test_neumann.test | 59 +
.../calcite/src/test/sql/types/blob/test_blob.test | 108 +
.../src/test/sql/types/blob/test_blob.test_ignore | 106 +
.../src/test/sql/types/blob/test_blob_cast.test | 71 +
.../test/sql/types/blob/test_blob_function.test | 84 +
.../test/sql/types/blob/test_blob_operator.test | 92 +
.../sql/types/blob/test_blob_operator.test_ignore | 65 +
.../src/test/sql/types/blob/test_blob_string.test | 35 +
.../test/sql/types/date/date_parsing.test_ignore | 344 +
.../test/sql/types/date/test_bc_dates.test_ignore | 87 +
.../src/test/sql/types/date/test_date.test_ignore | 71 +
.../test/sql/types/date/test_incorrect_dates.test | 54 +
.../test/sql/types/decimal/cast_from_decimal.test | 72 +
.../test/sql/types/decimal/cast_to_decimal.test | 248 +
.../test/sql/types/decimal/decimal_aggregates.test | 90 +
.../test/sql/types/decimal/decimal_arithmetic.test | 197 +
.../decimal/decimal_decimal_overflow_cast.test | 94 +
.../test/sql/types/decimal/decimal_overflow.test | 51 +
.../sql/types/decimal/decimal_overflow_table.test | 39 +
.../sql/types/decimal/large_decimal_constants.test | 43 +
.../src/test/sql/types/decimal/test_decimal.test | 151 +
.../sql/types/decimal/test_decimal_cast.test_slow | 87 +
.../test/sql/types/decimal/test_decimal_ops.test | 250 +
.../sql/types/interval/interval_constants.test | 152 +
.../src/test/sql/types/interval/test_interval.test | 163 +
.../sql/types/interval/test_interval_addition.test | 250 +
.../types/interval/test_interval_comparison.test | 31 +
.../test/sql/types/interval/test_interval_ops.test | 51 +
.../types/interval/test_interval_ops.test_ignore | 52 +
.../src/test/sql/types/list/array_agg.test_ignore | 60 +
.../src/test/sql/types/list/list.test_slow_ignore | 12 +
.../sql/types/list/list_aggregates.test_ignore | 63 +
.../src/test/sql/types/null/test_boolean_null.test | 36 +
.../src/test/sql/types/null/test_is_null.test | 24 +
.../calcite/src/test/sql/types/null/test_null.test | 66 +
.../src/test/sql/types/null/test_null_aggr.test | 52 +
.../test/sql/types/string/test_big_strings.test | 29 +
.../types/string/test_scan_big_varchar.test_slow | 152 +
.../sql/types/string/test_unicode.test_ignored | 33 +
.../src/test/sql/types/time/test_time.test_ignore | 32 +
.../test/sql/types/time/time_parsing.test_ignore | 62 +
.../sql/types/timestamp/bc_timestamp.test_ignore | 19 +
.../timestamp/test_incorrect_timestamp.test_ignore | 53 +
.../sql/types/timestamp/test_timestamp.test_ignore | 144 +
.../types/timestamp/test_timestamp_ms.test_ignore | 15 +
.../unsigned/test_unsigned_arithmetic.test_ignored | 99 +
.../unsigned/test_unsigned_auto_cast.test_ignored | 197 +
.../unsigned/test_unsigned_conversion.test_ignored | 507 +
.../src/test/sql/update/null_update_merge.test | 128 +
.../sql/update/test_big_string_update.test_ignore | 96 +
.../test/sql/update/test_null_update.test_ignore | 194 +
.../update/test_repeated_string_update.test_ignore | 62 +
.../test/sql/update/test_string_update.test_ignore | 66 +
.../test_string_update_many_strings.test_ignore | 128 +
.../sql/update/test_string_update_null.test_ignore | 40 +
.../update/test_string_update_rollback.test_ignore | 118 +
.../test_string_update_rollback_null.test_ignore | 89 +
.../src/test/sql/update/test_update.test_ignore | 80 +
.../test_update_delete_same_tuple.test_ignore | 44 +
.../test/sql/update/test_update_from.test_ignore | 160 +
.../update/test_update_many_updaters.test_ignore | 316 +
.../test_update_many_updaters_nulls.test_ignore | 119 +
.../test/sql/update/test_update_mix.test_ignore | 75 +
.../sql/update/test_update_same_value.test_ignore | 180 +
.../internal/jdbc2/JdbcMetadataSelfTest.java | 8 +-
.../ignite/jdbc/thin/JdbcThinMetadataSelfTest.java | 23 +-
modules/codegen/pom.xml | 6 +
.../ignite/codegen/MessageCodeGenerator.java | 3 +
.../SystemViewRowAttributeWalkerGenerator.java | 2 +
.../apache/ignite/util/SystemViewCommandTest.java | 6 +-
.../org/apache/ignite/IgniteSystemProperties.java | 35 +
.../configuration/QueryEngineConfiguration.java | 44 +
.../ignite/configuration/SqlConfiguration.java | 32 +
.../ignite/internal/GridKernalContextImpl.java | 4 +-
.../java/org/apache/ignite/internal/GridTopic.java | 5 +-
.../ignite/internal/IgniteComponentType.java | 9 +
.../org/apache/ignite/internal/IgniteKernal.java | 5 +
.../apache/ignite/internal/QueryMXBeanImpl.java | 25 +-
.../internal/jdbc/thin/ConnectionProperties.java | 12 +
.../jdbc/thin/ConnectionPropertiesImpl.java | 17 +-
.../ignite/internal/jdbc/thin/JdbcThinTcpIo.java | 13 +-
.../managers/communication/GridIoManager.java | 2 +
.../managers/communication/GridIoPolicy.java | 3 +
.../processors/cache/IgniteCacheProxyImpl.java | 4 +
.../internal/processors/cache/QueryCursorImpl.java | 2 +-
.../cache/persistence/metastorage/MetaStorage.java | 46 +-
.../cache/query/IgniteQueryErrorCode.java | 3 +
.../processors/cache/query/QueryCursorEx.java | 7 +
.../odbc/jdbc/JdbcConnectionContext.java | 33 +-
.../processors/odbc/jdbc/JdbcQueryCursor.java | 10 +-
.../processors/odbc/jdbc/JdbcRequestHandler.java | 27 +-
.../odbc/odbc/OdbcConnectionContext.java | 33 +-
.../processors/odbc/odbc/OdbcQueryResults.java | 4 +-
.../processors/odbc/odbc/OdbcRequestHandler.java | 6 +-
.../processors/odbc/odbc/OdbcResultSet.java | 8 +-
.../internal/processors/odbc/odbc/OdbcUtils.java | 4 +-
.../cache/query/PlatformContinuousQueryImpl.java | 8 +
.../internal/processors/pool/PoolProcessor.java | 4 +
.../internal/processors/query/GridQueryCancel.java | 5 +
.../processors/query/GridQueryIndexing.java | 17 +-
.../processors/query/GridQueryProcessor.java | 196 +-
.../processors/query/GridQuerySchemaManager.java | 47 +
.../processors/query/GridQueryTypeDescriptor.java | 17 +
.../processors/query/IndexingQueryEngine.java} | 27 +-
.../internal/processors/query/NoOpQueryEngine.java | 53 +
.../internal/processors/query/QueryContext.java | 74 +
.../internal/processors/query/QueryEngine.java} | 42 +-
.../query/QueryEngineConfigurationEx.java} | 29 +-
.../internal/processors/query/QueryEntityEx.java | 19 +
.../processors/query/QueryHistoryTracker.java | 2 +-
.../internal/processors/query/QueryState.java} | 37 +-
.../query/QuerySysIndexDescriptorImpl.java | 69 +
.../processors/query/QueryTypeDescriptorImpl.java | 19 +-
.../internal/processors/query/QueryUtils.java | 68 +-
.../internal/processors/query/RunningQuery.java} | 30 +-
.../processors/query/RunningQueryManager.java | 350 +-
.../processors/query/SqlClientContext.java | 26 +-
.../query/schema/SchemaChangeListener.java | 127 +
.../query/stat/IgniteStatisticsManager.java | 8 +
.../processors/query/stat/StatisticsKey.java | 12 +-
.../stat/config/StatisticsColumnConfiguration.java | 24 +-
.../stat/config/StatisticsObjectConfiguration.java | 11 +-
.../GridInternalSubscriptionProcessor.java | 16 +
.../ignite/internal/sql/SqlCommandProcessor.java | 364 +
.../internal/sql/command/SqlAlterTableCommand.java | 18 +
.../internal/sql/command/SqlAlterUserCommand.java | 18 +
.../sql/command/SqlCreateIndexCommand.java | 36 +
.../internal/sql/command/SqlCreateUserCommand.java | 18 +
.../internal/sql/command/SqlDropIndexCommand.java | 17 +
.../internal/sql/command/SqlDropUserCommand.java | 14 +
.../sql/command/SqlKillComputeTaskCommand.java | 14 +
.../sql/command/SqlKillContinuousQueryCommand.java | 17 +
.../internal/sql/command/SqlKillQueryCommand.java | 20 +
.../sql/command/SqlKillScanQueryCommand.java | 18 +
.../sql/command/SqlKillServiceCommand.java | 14 +
.../sql/command/SqlKillTransactionCommand.java | 14 +
.../apache/ignite/internal/util/IgniteUtils.java | 13 +-
.../internal/visor/query/VisorQueryCancelTask.java | 2 +-
.../ignite/startup/cmdline/CommandLineStartup.java | 4 +
.../apache/ignite/thread/SameThreadExecutor.java} | 31 +-
.../processors/query/DummyQueryIndexing.java | 13 +-
.../IndexingQueryEngineConfiguration.java} | 44 +-
.../org/apache/ignite/indexing/package-info.java | 22 +
.../managers/systemview/SystemViewLocal.java | 5 +
.../StatisticsColumnGlobalDataViewWalker.java | 90 +
.../metric/sql/MetricRegistryLocalSystemView.java | 7 +
.../processors/query/h2/CommandProcessor.java | 669 +-
.../internal/processors/query/h2/H2Utils.java | 8 +
.../processors/query/h2/IgniteH2Indexing.java | 42 +-
.../internal/processors/query/h2/QueryParser.java | 56 +-
.../processors/query/h2/SchemaManager.java | 287 +-
.../query/h2/database/H2PkHashIndex.java | 1 -
.../query/h2/database/H2TreeClientIndex.java | 9 +
.../processors/query/h2/database/H2TreeIndex.java | 11 +-
.../processors/query/h2/opt/GridH2IndexBase.java | 15 +
.../processors/query/h2/opt/GridH2Table.java | 12 +-
.../query/h2/sys/view/SqlSystemView.java | 7 +
.../h2/twostep/msg/GridH2ValueMessageFactory.java | 11 +
.../query/stat/IgniteGlobalStatisticsManager.java | 1021 +
.../stat/IgniteStatisticsConfigurationManager.java | 23 +-
.../query/stat/IgniteStatisticsHelper.java | 60 +
.../query/stat/IgniteStatisticsManagerImpl.java | 102 +-
.../query/stat/IgniteStatisticsRepository.java | 86 +-
.../query/stat/ObjectStatisticsEvent.java | 75 +
.../query/stat/ObjectStatisticsImpl.java | 16 +
.../StatisticsAddressedRequest.java} | 51 +-
.../processors/query/stat/StatisticsProcessor.java | 4 +-
.../processors/query/stat/StatisticsType.java | 5 +-
.../processors/query/stat/StatisticsUtils.java | 63 +-
.../query/stat/messages/StatisticsKeyMessage.java | 6 +
.../query/stat/messages/StatisticsRequest.java | 243 +
...ticsKeyMessage.java => StatisticsResponse.java} | 107 +-
.../stat/view/ColumnLocalDataViewSupplier.java | 4 +-
...ew.java => StatisticsColumnGlobalDataView.java} | 7 +-
.../stat/view/StatisticsColumnLocalDataView.java | 2 +-
.../cache/CacheSqlQueryValueCopySelfTest.java | 2 +-
.../processors/cache/index/BasicIndexTest.java | 4 +-
.../cache/metric/SqlViewExporterSpiTest.java | 6 +-
.../query/h2/TableStatisticsAbstractTest.java | 2 +-
.../stat/IgniteStatisticsRepositoryStaticTest.java | 84 +
.../query/stat/IgniteStatisticsRepositoryTest.java | 13 +-
...cValueDistributionTableStatisticsUsageTest.java | 2 +-
.../PSUCompositeIndexTableStatisticsUsageTest.java | 10 +-
.../stat/PSUStatisticPartialGatheringTest.java | 4 +-
.../query/stat/PSUStatisticsStorageTest.java | 12 +-
...UValueDistributionTableStatisticsUsageTest.java | 2 +-
.../query/stat/SqlStatisticsCommandTests.java | 5 +-
.../query/stat/StatisticsAbstractTest.java | 274 +-
.../processors/query/stat/StatisticsClearTest.java | 2 +-
.../query/stat/StatisticsConfigurationTest.java | 22 +-
.../query/stat/StatisticsGatheringTest.java | 70 +-
....java => StatisticsGlobalViewInMemoryTest.java} | 15 +-
...va => StatisticsGlobalViewPersistenceTest.java} | 15 +-
.../query/stat/StatisticsGlobalViewTest.java | 160 +
.../query/stat/StatisticsObsolescenceTest.java | 2 +-
.../query/stat/StatisticsRestartAbstractTest.java | 5 +-
.../query/stat/StatisticsStorageTest.java | 10 +-
.../query/stat/StatisticsTypesAbstractTest.java | 2 +-
.../processors/query/stat/StatisticsUtilsTest.java | 158 +
.../query/stat/StatisticsViewsInMemoryTest.java | 11 +-
.../query/stat/StatisticsViewsPersistenceTest.java | 11 +-
.../processors/query/stat/StatisticsViewsTest.java | 141 +-
.../testsuites/IgniteStatisticsTestSuite.java | 8 +
.../apache/ignite/util/KillCommandsMXBeanTest.java | 7 +-
.../cpp/common/include/ignite/common/utils.h | 23 +
modules/platforms/cpp/odbc-test/CMakeLists.txt | 4 +-
.../cpp/odbc-test/config/queries-default.xml | 15 +
.../cpp/odbc-test/src/configuration_test.cpp | 9 +
.../cpp/odbc-test/src/cross_engine_test.cpp | 126 +
modules/platforms/cpp/odbc/CMakeLists.txt | 1 +
.../include/ignite/odbc/config/configuration.h | 32 +
.../ignite/odbc/config/connection_string_parser.h | 3 +
.../cpp/odbc/include/ignite/odbc/engine_mode.h | 73 +
.../odbc/include/ignite/odbc/protocol_version.h | 3 +
.../odbc/system/ui/dsn_configuration_window.h | 8 +
.../win/src/system/ui/dsn_configuration_window.cpp | 60 +-
.../cpp/odbc/src/config/configuration.cpp | 26 +-
.../odbc/src/config/connection_string_parser.cpp | 18 +
modules/platforms/cpp/odbc/src/dsn_config.cpp | 5 +
modules/platforms/cpp/odbc/src/engine_mode.cpp | 77 +
modules/platforms/cpp/odbc/src/message.cpp | 10 +
.../platforms/cpp/odbc/src/protocol_version.cpp | 6 +-
parent/pom.xml | 13 +-
pom.xml | 1 +
960 files changed, 644856 insertions(+), 2824 deletions(-)
diff --git a/modules/benchmarks/pom.xml b/modules/benchmarks/pom.xml
index 4d55310..93b305d 100644
--- a/modules/benchmarks/pom.xml
+++ b/modules/benchmarks/pom.xml
@@ -52,6 +52,18 @@
</dependency>
<dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ignite-calcite</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <version>${javassist.version}</version>
+ </dependency>
+
+ <dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
diff --git a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/sql/JmhSqlBenchmark.java b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/sql/JmhSqlBenchmark.java
new file mode 100644
index 0000000..a4d231e
--- /dev/null
+++ b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/sql/JmhSqlBenchmark.java
@@ -0,0 +1,285 @@
+/*
+ * 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.ignite.internal.benchmarks.jmh.sql;
+
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteDataStreamer;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.cache.query.annotations.QuerySqlField;
+import org.apache.ignite.calcite.CalciteQueryEngineConfiguration;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.SqlConfiguration;
+import org.apache.ignite.indexing.IndexingQueryEngineConfiguration;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+/**
+ * Benchmark simple SQL queries.
+ */
+@State(Scope.Benchmark)
+@Fork(1)
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.SECONDS)
+@Warmup(iterations = 3, time = 5)
+@Measurement(iterations = 3, time = 5)
+public class JmhSqlBenchmark {
+ /** Count of server nodes. */
+ private static final int SRV_NODES_CNT = 3;
+
+ /** Keys count. */
+ private static final int KEYS_CNT = 100000;
+
+ /** Size of batch. */
+ private static final int BATCH_SIZE = 1000;
+
+ /** Partitions count. */
+ private static final int PARTS_CNT = 1024;
+
+ /** IP finder shared across nodes. */
+ private static final TcpDiscoveryVmIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+ /** Query engine. */
+ @Param({"H2", "CALCITE"})
+ private String engine;
+
+ /** Ignite client. */
+ private Ignite client;
+
+ /** Servers. */
+ private final Ignite[] servers = new Ignite[SRV_NODES_CNT];
+
+ /** Cache. */
+ private IgniteCache<Integer, Item> cache;
+
+ /**
+ * Create Ignite configuration.
+ *
+ * @param igniteInstanceName Ignite instance name.
+ * @return Configuration.
+ */
+ private IgniteConfiguration configuration(String igniteInstanceName) {
+ IgniteConfiguration cfg = new IgniteConfiguration();
+
+ cfg.setIgniteInstanceName(igniteInstanceName);
+ cfg.setLocalHost("127.0.0.1");
+ cfg.setDiscoverySpi(new TcpDiscoverySpi().setIpFinder(IP_FINDER));
+ cfg.setSqlConfiguration(new SqlConfiguration().setQueryEnginesConfiguration(
+ "CALCITE".equals(engine) ? new CalciteQueryEngineConfiguration() : new IndexingQueryEngineConfiguration()
+ ));
+
+ return cfg;
+ }
+
+ /**
+ * Initiate Ignite and caches.
+ */
+ @Setup(Level.Trial)
+ public void setup() {
+ for (int i = 0; i < SRV_NODES_CNT; i++)
+ servers[i] = Ignition.start(configuration("server" + i));
+
+ client = Ignition.start(configuration("client").setClientMode(true));
+
+ cache = client.getOrCreateCache(new CacheConfiguration<Integer, Item>("CACHE")
+ .setIndexedTypes(Integer.class, Item.class)
+ .setAffinity(new RendezvousAffinityFunction(false, PARTS_CNT))
+ );
+
+ try (IgniteDataStreamer<Integer, Item> ds = client.dataStreamer("CACHE")) {
+ for (int i = 0; i < KEYS_CNT; i++)
+ ds.addData(i, new Item(i));
+ }
+ }
+
+ /**
+ * Stop Ignite instance.
+ */
+ @TearDown
+ public void tearDown() {
+ client.close();
+
+ for (Ignite ignite : servers)
+ ignite.close();
+ }
+
+ /**
+ * Query unique value (full scan).
+ */
+ @Benchmark
+ public void querySimpleUnique() {
+ int key = ThreadLocalRandom.current().nextInt(KEYS_CNT);
+
+ List<?> res = executeSql("SELECT name FROM Item WHERE fld=?", key);
+
+ assert res.size() == 1;
+ }
+
+ /**
+ * Query unique value (indexed).
+ */
+ @Benchmark
+ public void querySimpleUniqueIndexed() {
+ int key = ThreadLocalRandom.current().nextInt(KEYS_CNT);
+
+ List<?> res = executeSql("SELECT name FROM Item WHERE fldIdx=?", key);
+
+ assert res.size() == 1;
+ }
+
+ /**
+ * Query batch (full scan).
+ */
+ @Benchmark
+ public void querySimpleBatch() {
+ int key = ThreadLocalRandom.current().nextInt(KEYS_CNT);
+
+ List<?> res = executeSql("SELECT name FROM Item WHERE fldBatch=?", key / BATCH_SIZE);
+
+ assert res.size() == BATCH_SIZE;
+ }
+
+ /**
+ * Query batch (indexed).
+ */
+ @Benchmark
+ public void querySimpleBatchIndexed() {
+ int key = ThreadLocalRandom.current().nextInt(KEYS_CNT);
+
+ List<?> res = executeSql("SELECT name FROM Item WHERE fldIdxBatch=?", key / BATCH_SIZE);
+
+ assert res.size() == BATCH_SIZE;
+ }
+
+ /**
+ * Query with group by and aggregate.
+ */
+ @Benchmark
+ public void queryGroupBy() {
+ List<?> res = executeSql("SELECT fldBatch, AVG(fld) FROM Item GROUP BY fldBatch");
+
+ assert res.size() == KEYS_CNT / BATCH_SIZE;
+ }
+
+ /**
+ * Query with indexed field group by and aggregate.
+ */
+ @Benchmark
+ public void queryGroupByIndexed() {
+ List<?> res = executeSql("SELECT fldIdxBatch, AVG(fld) FROM Item GROUP BY fldIdxBatch");
+
+ assert res.size() == KEYS_CNT / BATCH_SIZE;
+ }
+
+ /**
+ * Query with sorting (full set).
+ */
+ @Benchmark
+ public void queryOrderByFull() {
+ List<?> res = executeSql("SELECT name, fld FROM Item ORDER BY fld DESC");
+
+ assert res.size() == KEYS_CNT;
+ }
+
+ /**
+ * Query with sorting (batch).
+ */
+ @Benchmark
+ public void queryOrderByBatch() {
+ int key = ThreadLocalRandom.current().nextInt(KEYS_CNT);
+
+ List<?> res = executeSql("SELECT name, fld FROM Item WHERE fldIdxBatch=? ORDER BY fld DESC", key / BATCH_SIZE);
+
+ assert res.size() == BATCH_SIZE;
+ }
+
+ /** */
+ private List<?> executeSql(String sql, Object... args) {
+ List<List<?>> res = cache.query(new SqlFieldsQuery(sql).setArgs(args)).getAll();
+
+ return res.get(0);
+ }
+
+ /**
+ * Run benchmarks.
+ *
+ * @param args Args.
+ * @throws Exception Exception.
+ */
+ public static void main(String[] args) throws Exception {
+ final Options options = new OptionsBuilder()
+ .include(JmhSqlBenchmark.class.getSimpleName())
+ .build();
+
+ new Runner(options).run();
+ }
+
+ /** */
+ private static class Item {
+ /** */
+ @QuerySqlField
+ private final String name;
+
+ /** */
+ @QuerySqlField
+ private final int fld;
+
+ /** */
+ @QuerySqlField
+ private final int fldBatch;
+
+ /** */
+ @QuerySqlField(index = true)
+ private final int fldIdx;
+
+ /** */
+ @QuerySqlField(index = true)
+ private final int fldIdxBatch;
+
+ /** */
+ public Item(int val) {
+ name = "name" + val;
+ fld = val;
+ fldBatch = val / BATCH_SIZE;
+ fldIdx = val;
+ fldIdxBatch = val / BATCH_SIZE;
+ }
+ }
+}
diff --git a/modules/calcite/README.txt b/modules/calcite/README.txt
new file mode 100644
index 0000000..8316403
--- /dev/null
+++ b/modules/calcite/README.txt
@@ -0,0 +1,38 @@
+Apache Ignite Calcite Module
+--------------------------
+
+Apache Ignite Calcite module provides experimental Apache Calcite based query engine.
+
+To enable Calcite based engine explicit `CalciteQueryEngineConfiguration` instance should be added to
+`SqlConfiguration.QueryEnginesConfiguration` property (see `SqlConfiguration.setQueryEnginesConfiguration()`).
+Also, Calcite module libraries should be in a classpath.
+
+When starting a standalone node, move 'optional/ignite-calcite' folder to 'libs' folder before running
+'ignite.{sh|bat}' script. The content of the module folder will be added to classpath in this case.
+
+Note: At now some logic from ignite-indexing module is reused, this means ignite-indexing module also
+has to be present at classpath.
+
+Importing Calcite Module In Maven Project
+---------------------------------------
+
+If you are using Maven to manage dependencies of your project, you can add Calcite module
+dependency like this (replace '${ignite.version}' with actual Apache Ignite version you are
+interested in):
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+ http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ ...
+ <dependencies>
+ ...
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-calcite</artifactId>
+ <version>${ignite.version}</version>
+ </dependency>
+ ...
+ </dependencies>
+ ...
+</project>
diff --git a/modules/calcite/pom.xml b/modules/calcite/pom.xml
new file mode 100644
index 0000000..dcb39b0
--- /dev/null
+++ b/modules/calcite/pom.xml
@@ -0,0 +1,312 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<!--
+ POM file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- Module specific package versions -->
+ <properties>
+ <avatica.version>1.19.0</avatica.version>
+ <calcite.version>1.29.0</calcite.version>
+ <checker.version>3.10.0</checker.version>
+ <esri.geometry.version>2.2.0</esri.geometry.version>
+ <immutables.version>2.8.2</immutables.version>
+ <janino.version>3.1.6</janino.version>
+ <javacc-maven-plugin>2.4</javacc-maven-plugin>
+ <!-- <javassist.version>3.28.0-GA</javassist.version>-->
+ <jsonpath.version>2.4.0</jsonpath.version>
+ <reflections.version>0.10.2</reflections.version>
+ </properties>
+
+ <parent>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-parent</artifactId>
+ <version>1</version>
+ <relativePath>../../parent</relativePath>
+ </parent>
+
+ <artifactId>ignite-calcite</artifactId>
+ <version>${revision}</version>
+ <url>http://ignite.apache.org</url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!--
+ At now the new calcite engine reuses some logic
+ and doesn't work without "old" indexing module.
+ -->
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-indexing</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.calcite</groupId>
+ <artifactId>calcite-core</artifactId>
+ <version>${calcite.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.calcite</groupId>
+ <artifactId>calcite-linq4j</artifactId>
+ <version>${calcite.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>${guava.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.checkerframework</groupId>
+ <artifactId>checker-qual</artifactId>
+ <version>${checker.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.codehaus.janino</groupId>
+ <artifactId>commons-compiler</artifactId>
+ <version>${janino.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.codehaus.janino</groupId>
+ <artifactId>janino</artifactId>
+ <version>${janino.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.calcite.avatica</groupId>
+ <artifactId>avatica-core</artifactId>
+ <version>${avatica.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.jayway.jsonpath</groupId>
+ <artifactId>json-path</artifactId>
+ <version>${jsonpath.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.reflections</groupId>
+ <artifactId>reflections</artifactId>
+ <version>${reflections.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <version>${javassist.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.esri.geometry</groupId>
+ <artifactId>esri-geometry-api</artifactId>
+ <version>${esri.geometry.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.immutables</groupId>
+ <artifactId>value</artifactId>
+ <version>${immutables.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-core</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ignite-tools</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-core</artifactId>
+ <version>${spring.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>${slf4j.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-beans</artifactId>
+ <version>${spring.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <version>${spring.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ignite</groupId>
+ <artifactId>ignite-clients</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <!-- Generate the OSGi MANIFEST.MF for this bundle. -->
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-fmpp-resources</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/codegen</outputDirectory>
+ <resources>
+ <resource>
+ <directory>src/main/codegen</directory>
+ <filtering>false</filtering>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-parser-template</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.apache.calcite</groupId>
+ <artifactId>calcite-core</artifactId>
+ <type>jar</type>
+ <overWrite>true</overWrite>
+ <outputDirectory>${project.build.directory}/</outputDirectory>
+ <includes>codegen/templates/Parser.jj</includes>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>com.googlecode.fmpp-maven-plugin</groupId>
+ <artifactId>fmpp-maven-plugin</artifactId>
+ <version>1.0</version>
+ <configuration>
+ <cfgFile>${project.build.directory}/codegen/config.fmpp</cfgFile>
+ <templateDirectory>${project.build.directory}/codegen/templates</templateDirectory>
+ </configuration>
+ <executions>
+ <execution>
+ <id>generate-fmpp-sources</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>javacc-maven-plugin</artifactId>
+ <version>${javacc-maven-plugin}</version>
+ <executions>
+ <execution>
+ <id>javacc</id>
+ <goals>
+ <goal>javacc</goal>
+ </goals>
+ <configuration>
+ <sourceDirectory>${project.build.directory}/generated-sources/fmpp</sourceDirectory>
+ <outputDirectory>${project.build.sourceDirectory}</outputDirectory>
+ <includes>
+ <include>**/Parser.jj</include>
+ </includes>
+ <lookAhead>2</lookAhead>
+ <isStatic>false</isStatic>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/modules/calcite/src/main/codegen/config.fmpp b/modules/calcite/src/main/codegen/config.fmpp
new file mode 100644
index 0000000..f692ad7
--- /dev/null
+++ b/modules/calcite/src/main/codegen/config.fmpp
@@ -0,0 +1,691 @@
+# 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.
+
+data: {
+ # Data declarations for this parser.
+ #
+ # Default declarations are in default_config.fmpp; if you do not include a
+ # declaration ('imports' or 'nonReservedKeywords', for example) in this file,
+ # FMPP will use the declaration from default_config.fmpp.
+ parser: {
+ # Generated parser implementation class package and name
+ package: "org.apache.ignite.internal.processors.query.calcite.sql.generated",
+ class: "IgniteSqlParserImpl",
+
+ # List of additional classes and packages to import.
+ # Example: "org.apache.calcite.sql.*", "java.util.List".
+ imports: [
+ "java.util.UUID",
+ "org.apache.calcite.sql.SqlCreate",
+ "org.apache.calcite.sql.SqlDrop",
+ "org.apache.calcite.sql.SqlLiteral",
+ "org.apache.calcite.schema.ColumnStrategy",
+ "org.apache.ignite.internal.processors.query.calcite.util.IgniteResource",
+ "org.apache.ignite.lang.IgniteUuid",
+ "org.apache.calcite.sql.ddl.SqlDdlNodes",
+ "org.apache.ignite.internal.processors.query.calcite.sql.*",
+ ]
+
+ # List of new keywords. Example: "DATABASES", "TABLES". If the keyword is
+ # not a reserved keyword, add it to the 'nonReservedKeywords' section.
+ keywords: [
+ "SEMI"
+ "IF"
+ "TEMPLATE"
+ "BACKUPS"
+ "AFFINITY_KEY"
+ "ATOMICITY"
+ "WRITE_SYNCHRONIZATION_MODE"
+ "CACHE_GROUP"
+ "CACHE_NAME"
+ "DATA_REGION"
+# "KEY_TYPE" // already presented in Calcite
+ "VALUE_TYPE"
+ "ENCRYPTED"
+ "INDEX"
+ "PARALLEL"
+ "INLINE_SIZE"
+ "LOGGING"
+ "NOLOGGING"
+ "PASSWORD"
+ "KILL"
+ "SCAN"
+ "CONTINUOUS"
+ "SERVICE"
+ "COMPUTE"
+ "ASYNC"
+ "QUERY"
+ "UUID"
+ ]
+
+ # List of non-reserved keywords to add;
+ # items in this list become non-reserved
+ nonReservedKeywords: [
+ "SEMI"
+ "TEMPLATE"
+ "BACKUPS"
+ "AFFINITY_KEY"
+ "ATOMICITY"
+ "WRITE_SYNCHRONIZATION_MODE"
+ "CACHE_GROUP"
+ "CACHE_NAME"
+ "DATA_REGION"
+# "KEY_TYPE" // already presented in Calcite
+ "VALUE_TYPE"
+ "ENCRYPTED"
+ "PARALLEL"
+ "INLINE_SIZE"
+ "LOGGING"
+ "NOLOGGING"
+ "PASSWORD"
+ "KILL"
+ "SCAN"
+ "CONTINUOUS"
+ "SERVICE"
+ "COMPUTE"
+ "ASYNC"
+ "QUERY"
+ "UUID"
+
+ # The following keywords are reserved in core Calcite,
+ # are reserved in some version of SQL,
+ # but are not reserved in Babel.
+ #
+ # Words that are commented out (e.g. "AND") are still reserved.
+ # These are the most important reserved words, and SQL cannot be
+ # unambiguously parsed if they are not reserved. For example, if
+ # "INNER" is not reserved then in the query
+ #
+ # select * from emp inner join dept using (deptno)"
+ #
+ # "inner" could be a table alias for "emp".
+ #
+ "A"
+ "ABS"
+ "ABSOLUTE"
+ "ACTION"
+ "ADD"
+ "AFTER"
+# "ALL"
+ "ALLOCATE"
+ "ALLOW"
+ "ALTER"
+ "AND"
+# "ANY"
+ "ARE"
+ "ARRAY"
+# "ARRAY_AGG" # not a keyword in Calcite
+ "ARRAY_MAX_CARDINALITY"
+ "AS"
+ "ASC"
+ "ASENSITIVE"
+ "ASSERTION"
+ "ASYMMETRIC"
+ "AT"
+ "ATOMIC"
+ "AUTHORIZATION"
+ "AVG"
+ "BEFORE"
+ "BEGIN"
+ "BEGIN_FRAME"
+ "BEGIN_PARTITION"
+ "BETWEEN"
+ "BIGINT"
+ "BINARY"
+ "BIT"
+# "BIT_LENGTH" # not a keyword in Calcite
+ "BLOB"
+ "BOOLEAN"
+ "BOTH"
+ "BREADTH"
+ "BY"
+ "C"
+# "CALL"
+ "CALLED"
+ "CARDINALITY"
+ "CASCADE"
+ "CASCADED"
+# "CASE"
+ "CAST"
+ "CATALOG"
+ "CEIL"
+ "CEILING"
+ "CHAR"
+ "CHARACTER"
+ "CHARACTER_LENGTH"
+ "CHAR_LENGTH"
+ "CHECK"
+ "CLASSIFIER"
+ "CLOB"
+ "CLOSE"
+ "COALESCE"
+ "COLLATE"
+ "COLLATION"
+ "COLLECT"
+ "COLUMN"
+ "COMMIT"
+ "CONDITION"
+ "CONNECT"
+ "CONNECTION"
+# "CONSTRAINT"
+ "CONSTRAINTS"
+ "CONSTRUCTOR"
+ "CONTAINS"
+ "CONTINUE"
+ "CONVERT"
+ "CORR"
+ "CORRESPONDING"
+ "COUNT"
+ "COVAR_POP"
+ "COVAR_SAMP"
+# "CREATE"
+# "CROSS"
+ "CUBE"
+ "CUME_DIST"
+# "CURRENT"
+ "CURRENT_CATALOG"
+ "CURRENT_DATE"
+ "CURRENT_DEFAULT_TRANSFORM_GROUP"
+ "CURRENT_PATH"
+ "CURRENT_ROLE"
+ "CURRENT_ROW"
+ "CURRENT_SCHEMA"
+ "CURRENT_TIME"
+ "CURRENT_TIMESTAMP"
+ "CURRENT_TRANSFORM_GROUP_FOR_TYPE"
+ "CURRENT_USER"
+# "CURSOR"
+ "CYCLE"
+ "DATA"
+ "DATE"
+ "DAY"
+ "DEALLOCATE"
+ "DEC"
+ "DECIMAL"
+ "DECLARE"
+# "DEFAULT"
+ "DEFERRABLE"
+ "DEFERRED"
+# "DEFINE"
+# "DELETE"
+ "DENSE_RANK"
+ "DEPTH"
+ "DEREF"
+ "DESC"
+# "DESCRIBE" # must be reserved
+ "DESCRIPTOR"
+ "DETERMINISTIC"
+ "DIAGNOSTICS"
+ "DISALLOW"
+ "DISCONNECT"
+# "DISTINCT"
+# "DO" # not a keyword in Calcite
+ "DOMAIN"
+ "DOUBLE"
+# "DROP" # probably must be reserved
+ "DYNAMIC"
+ "EACH"
+ "ELEMENT"
+ "ELSE"
+# "ELSEIF" # not a keyword in Calcite
+ "EMPTY"
+ "END"
+# "END-EXEC" # not a keyword in Calcite, and contains '-'
+ "END_FRAME"
+ "END_PARTITION"
+ "EQUALS"
+ "ESCAPE"
+ "EVERY"
+# "EXCEPT" # must be reserved
+ "EXCEPTION"
+ "EXEC"
+ "EXECUTE"
+ "EXISTS"
+# "EXIT" # not a keyword in Calcite
+ "EXP"
+# "EXPLAIN" # must be reserved
+ "EXTEND"
+ "EXTERNAL"
+ "EXTRACT"
+ "FALSE"
+# "FETCH"
+ "FILTER"
+ "FIRST"
+ "FIRST_VALUE"
+ "FLOAT"
+ "FLOOR"
+ "FOR"
+ "FOREIGN"
+# "FOREVER" # not a keyword in Calcite
+ "FOUND"
+ "FRAME_ROW"
+ "FREE"
+# "FROM" # must be reserved
+# "FULL" # must be reserved
+ "FUNCTION"
+ "FUSION"
+ "G"
+ "GENERAL"
+ "GET"
+ "GLOBAL"
+ "GO"
+ "GOTO"
+# "GRANT"
+# "GROUP"
+# "GROUPING"
+ "GROUPS"
+# "HANDLER" # not a keyword in Calcite
+# "HAVING"
+ "HOLD"
+ "HOUR"
+ "IDENTITY"
+# "IF" # not a keyword in Calcite
+ # "ILIKE"
+ "IMMEDIATE"
+ "IMMEDIATELY"
+ "IMPORT"
+# "IN"
+ "INDICATOR"
+ "INITIAL"
+ "INITIALLY"
+# "INNER"
+ "INOUT"
+ "INPUT"
+ "INSENSITIVE"
+# "INSERT"
+ "INT"
+ "INTEGER"
+# "INTERSECT"
+ "INTERSECTION"
+# "INTERVAL"
+# "INTO"
+ "IS"
+ "ISOLATION"
+# "ITERATE" # not a keyword in Calcite
+# "JOIN"
+ "JSON_ARRAY"
+ "JSON_ARRAYAGG"
+ "JSON_EXISTS"
+ "JSON_OBJECT"
+ "JSON_OBJECTAGG"
+ "JSON_QUERY"
+ "JSON_VALUE"
+ "K"
+# "KEEP" # not a keyword in Calcite
+ "KEY"
+ "LAG"
+ "LANGUAGE"
+ "LARGE"
+ "LAST"
+ "LAST_VALUE"
+# "LATERAL"
+ "LEAD"
+ "LEADING"
+# "LEAVE" # not a keyword in Calcite
+# "LEFT"
+ "LENGTH"
+ "LEVEL"
+ "LIKE"
+ "LIKE_REGEX"
+# "LIMIT"
+ "LN"
+ "LOCAL"
+ "LOCALTIME"
+ "LOCALTIMESTAMP"
+ "LOCATOR"
+# "LOOP" # not a keyword in Calcite
+ "LOWER"
+ "M"
+ "MAP"
+ "MATCH"
+ "MATCHES"
+ "MATCH_NUMBER"
+# "MATCH_RECOGNIZE"
+ "MAX"
+# "MAX_CARDINALITY" # not a keyword in Calcite
+ "MEASURES"
+ "MEMBER"
+# "MERGE"
+ "METHOD"
+ "MIN"
+# "MINUS"
+ "MINUTE"
+ "MOD"
+ "MODIFIES"
+ "MODULE"
+ "MONTH"
+ "MULTISET"
+ "NAME"
+ "NAMES"
+ "NATIONAL"
+# "NATURAL"
+ "NCHAR"
+ "NCLOB"
+# "NEW"
+# "NEXT"
+ "NO"
+ "NONE"
+ "NORMALIZE"
+ "NOT"
+ "NTH_VALUE"
+ "NTILE"
+# "NULL"
+ "NULLIF"
+ "NUMERIC"
+ "OBJECT"
+ "OCCURRENCES_REGEX"
+ "OCTET_LENGTH"
+ "OF"
+# "OFFSET"
+ "OLD"
+ "OMIT"
+# "ON"
+ "ONE"
+ "ONLY"
+ "OPEN"
+ "OPTION"
+ "OR"
+# "ORDER"
+ "ORDINALITY"
+ "OUT"
+# "OUTER"
+ "OUTPUT"
+# "OVER"
+ "OVERLAPS"
+ "OVERLAY"
+ "PAD"
+ "PARAMETER"
+ "PARTIAL"
+# "PARTITION"
+ "PATH"
+# "PATTERN"
+ "PER"
+ "PERCENT"
+ "PERCENTILE_CONT"
+ "PERCENTILE_DISC"
+ "PERCENT_RANK"
+ "PERIOD"
+ "PERMUTE"
+ "PORTION"
+ "POSITION"
+ "POSITION_REGEX"
+ "POWER"
+ "PRECEDES"
+ "PRECISION"
+ "PREPARE"
+ "PRESERVE"
+ "PREV"
+# "PRIMARY"
+ "PRIOR"
+ "PRIVILEGES"
+ "PROCEDURE"
+ "PUBLIC"
+ "QUARTER"
+# "RANGE"
+ "RANK"
+ "READ"
+ "READS"
+ "REAL"
+ "RECURSIVE"
+ "REF"
+ "REFERENCES"
+ "REFERENCING"
+ "REGR_AVGX"
+ "REGR_AVGY"
+ "REGR_COUNT"
+ "REGR_INTERCEPT"
+ "REGR_R2"
+ "REGR_SLOPE"
+ "REGR_SXX"
+ "REGR_SXY"
+ "REGR_SYY"
+ "RELATIVE"
+ "RELEASE"
+# "REPEAT" # not a keyword in Calcite
+ "REPLACE"
+ "RESET"
+# "RESIGNAL" # not a keyword in Calcite
+ "RESTRICT"
+ "RESULT"
+ "RETURN"
+ "RETURNS"
+ "REVOKE"
+# "RIGHT"
+ # "RLIKE"
+ "ROLE"
+ "ROLLBACK"
+# "ROLLUP"
+ "ROUTINE"
+# "ROW"
+# "ROWS"
+ "ROW_NUMBER"
+ "RUNNING"
+ "SAVEPOINT"
+ "SCHEMA"
+ "SCOPE"
+ "SCROLL"
+ "SEARCH"
+ "SECOND"
+ "SECTION"
+ "SEEK"
+# "SELECT"
+ "SENSITIVE"
+ "SESSION"
+ "SESSION_USER"
+# "SET"
+# "SETS"
+ "SHOW"
+# "SIGNAL" # not a keyword in Calcite
+ "SIMILAR"
+ "SIZE"
+# "SKIP" # messes with JavaCC's <SKIP> token
+ "SMALLINT"
+# "SOME"
+ "SPACE"
+ "SPECIFIC"
+ "SPECIFICTYPE"
+ "SQL"
+# "SQLCODE" # not a keyword in Calcite
+# "SQLERROR" # not a keyword in Calcite
+ "SQLEXCEPTION"
+ "SQLSTATE"
+ "SQLWARNING"
+ "SQRT"
+ "START"
+ "STATE"
+ "STATIC"
+ "STDDEV_POP"
+ "STDDEV_SAMP"
+# "STREAM"
+ "SUBMULTISET"
+ "SUBSET"
+ "SUBSTRING"
+ "SUBSTRING_REGEX"
+ "SUCCEEDS"
+ "SUM"
+ "SYMMETRIC"
+ "SYSTEM"
+ "SYSTEM_TIME"
+ "SYSTEM_USER"
+# "TABLE"
+# "TABLESAMPLE"
+ "TEMPORARY"
+# "THEN"
+# "TIME"
+# "TIMESTAMP"
+ "TIMEZONE_HOUR"
+ "TIMEZONE_MINUTE"
+ "TINYINT"
+ "TO"
+ "TRAILING"
+ "TRANSACTION"
+ "TRANSLATE"
+ "TRANSLATE_REGEX"
+ "TRANSLATION"
+ "TREAT"
+ "TRIGGER"
+ "TRIM"
+ "TRIM_ARRAY"
+ "TRUE"
+ "TRUNCATE"
+ "UESCAPE"
+ "UNDER"
+# "UNDO" # not a keyword in Calcite
+# "UNION"
+ "UNIQUE"
+ "UNKNOWN"
+# "UNNEST"
+# "UNTIL" # not a keyword in Calcite
+# "UPDATE"
+ "UPPER"
+ "UPSERT"
+ "USAGE"
+ "USER"
+# "USING"
+ "VALUE"
+# "VALUES"
+ "VALUE_OF"
+ "VARBINARY"
+ "VARCHAR"
+ "VARYING"
+ "VAR_POP"
+ "VAR_SAMP"
+ "VERSION"
+ "VERSIONING"
+# "VERSIONS" # not a keyword in Calcite
+ "VIEW"
+ "WEEK"
+# "WHEN"
+ "WHENEVER"
+# "WHERE"
+# "WHILE" # not a keyword in Calcite
+ "WIDTH_BUCKET"
+# "WINDOW"
+# "WITH"
+ "WITHIN"
+ "WITHOUT"
+ "WORK"
+ "WRITE"
+ "YEAR"
+ "ZONE"
+ ]
+
+ # List of non-reserved keywords to add;
+ # items in this list become non-reserved.
+ nonReservedKeywordsToAdd: [
+ ]
+
+ # List of non-reserved keywords to remove;
+ # items in this list become reserved.
+ nonReservedKeywordsToRemove: [
+ ]
+
+ # List of additional join types. Each is a method with no arguments.
+ # Example: "LeftSemiJoin".
+ joinTypes: [
+ # "LeftSemiJoin"
+ ]
+
+ # List of methods for parsing builtin function calls.
+ # Return type of method implementation should be "SqlNode".
+ # Example: "DateFunctionCall()".
+ builtinFunctionCallMethods: [
+ # "DateFunctionCall()"
+ # "DateaddFunctionCall()"
+ ]
+
+ # List of methods for parsing custom SQL statements.
+ # Return type of method implementation should be 'SqlNode'.
+ # Example: "SqlShowDatabases()", "SqlShowTables()".
+ statementParserMethods: [
+ "SqlAlterTable()",
+ "SqlAlterUser()",
+ "SqlKillScanQuery()",
+ "SqlKillContinuousQuery()",
+ "SqlKillService()",
+ "SqlKillTransaction()",
+ "SqlKillComputeTask()",
+ "SqlKillQuery()",
+ "SqlCommitTransaction()",
+ "SqlRollbackTransaction()"
+ ]
+
+ # List of methods for parsing extensions to "CREATE [OR REPLACE]" calls.
+ # Each must accept arguments "(SqlParserPos pos, boolean replace)".
+ # Example: "SqlCreateForeignSchema".
+ createStatementParserMethods: [
+ "SqlCreateTable",
+ "SqlCreateIndex",
+ "SqlCreateUser"
+ ]
+
+ # List of methods for parsing extensions to "DROP" calls.
+ # Each must accept arguments "(SqlParserPos pos)".
+ # Example: "SqlDropSchema".
+ dropStatementParserMethods: [
+ "SqlDropTable",
+ "SqlDropIndex",
+ "SqlDropUser"
+ ]
+
+ # List of methods for parsing extensions to "ALTER <scope>" calls.
+ # Where scope is SYSTEM or SESSION.
+ # Each must accept arguments "(SqlParserPos pos, String scope)".
+ alterStatementParserMethods: [
+ ]
+
+ # List of methods for parsing custom literals.
+ # Return type of method implementation should be "SqlNode".
+ # Example: ParseJsonLiteral().
+ literalParserMethods: [
+ ]
+
+ # List of methods for parsing custom data types.
+ # Return type of method implementation should be "SqlTypeNameSpec".
+ # Example: SqlParseTimeStampZ().
+ dataTypeParserMethods: [
+ ]
+
+ # Binary operators tokens.
+ # Example: "< INFIX_CAST: \"::\" >".
+ binaryOperatorsTokens: [
+ "< INFIX_CAST: \"::\" >"
+ ]
+
+ # Binary operators initialization.
+ # Example: "InfixCast".
+ extraBinaryExpressions: [
+ "InfixCast"
+ ]
+
+ # List of files in @includes directory that have parser method
+ # implementations for parsing custom SQL statements, literals or types
+ # given as part of "statementParserMethods", "literalParserMethods" or
+ # "dataTypeParserMethods".
+ # Example: "parserImpls.ftl".
+ implementationFiles: [
+ "parserImpls.ftl"
+ ]
+
+ includePosixOperators: true
+ includeCompoundIdentifier: true
+ includeBraces: true
+ includeAdditionalDeclarations: false
+ }
+}
+
+freemarkerLinks: {
+ includes: includes/
+}
diff --git a/modules/calcite/src/main/codegen/includes/parserImpls.ftl b/modules/calcite/src/main/codegen/includes/parserImpls.ftl
new file mode 100644
index 0000000..221e903
--- /dev/null
+++ b/modules/calcite/src/main/codegen/includes/parserImpls.ftl
@@ -0,0 +1,620 @@
+<#--
+// 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.
+-->
+
+boolean IfNotExistsOpt() :
+{
+}
+{
+ <IF> <NOT> <EXISTS> { return true; }
+|
+ { return false; }
+}
+
+SqlNodeList WithCreateTableOptionList() :
+{
+ List<SqlNode> list = new ArrayList<SqlNode>();
+ final Span s;
+}
+{
+ [
+ <WITH> { s = span(); }
+ CreateTableOption(list)
+ (
+ <COMMA> { s.add(this); } CreateTableOption(list)
+ )*
+ {
+ return new SqlNodeList(list, s.end(this));
+ }
+ ]
+ { return null; }
+}
+
+SqlLiteral CreateTableOptionKey() :
+{
+}
+{
+ <TEMPLATE> { return SqlLiteral.createSymbol(IgniteSqlCreateTableOptionEnum.TEMPLATE, getPos()); }
+|
+ <BACKUPS> { return SqlLiteral.createSymbol(IgniteSqlCreateTableOptionEnum.BACKUPS, getPos()); }
+|
+ <AFFINITY_KEY> { return SqlLiteral.createSymbol(IgniteSqlCreateTableOptionEnum.AFFINITY_KEY, getPos()); }
+|
+ <ATOMICITY> { return SqlLiteral.createSymbol(IgniteSqlCreateTableOptionEnum.ATOMICITY, getPos()); }
+|
+ <WRITE_SYNCHRONIZATION_MODE> { return SqlLiteral.createSymbol(IgniteSqlCreateTableOptionEnum.WRITE_SYNCHRONIZATION_MODE, getPos()); }
+|
+ <CACHE_GROUP> { return SqlLiteral.createSymbol(IgniteSqlCreateTableOptionEnum.CACHE_GROUP, getPos()); }
+|
+ <CACHE_NAME> { return SqlLiteral.createSymbol(IgniteSqlCreateTableOptionEnum.CACHE_NAME, getPos()); }
+|
+ <DATA_REGION> { return SqlLiteral.createSymbol(IgniteSqlCreateTableOptionEnum.DATA_REGION, getPos()); }
+|
+ <KEY_TYPE> { return SqlLiteral.createSymbol(IgniteSqlCreateTableOptionEnum.KEY_TYPE, getPos()); }
+|
+ <VALUE_TYPE> { return SqlLiteral.createSymbol(IgniteSqlCreateTableOptionEnum.VALUE_TYPE, getPos()); }
+|
+ <ENCRYPTED> { return SqlLiteral.createSymbol(IgniteSqlCreateTableOptionEnum.ENCRYPTED, getPos()); }
+}
+
+void CreateTableOption(List<SqlNode> list) :
+{
+ final Span s;
+ final SqlLiteral key;
+ final SqlNode val;
+}
+{
+ key = CreateTableOptionKey() { s = span(); }
+ <EQ>
+ (
+ val = Literal()
+ |
+ val = SimpleIdentifier()
+ ) {
+ list.add(new IgniteSqlCreateTableOption(key, val, s.end(this)));
+ }
+}
+
+SqlDataTypeSpec DataTypeEx() :
+{
+ final SqlDataTypeSpec dt;
+}
+{
+ (
+ dt = DataType()
+ |
+ dt = IntervalType()
+ |
+ dt = UuidType()
+ )
+ {
+ return dt;
+ }
+}
+
+SqlDataTypeSpec IntervalType() :
+{
+ final Span s;
+ final SqlIntervalQualifier intervalQualifier;
+}
+{
+ <INTERVAL> { s = span(); } intervalQualifier = IntervalQualifier() {
+ return new SqlDataTypeSpec(new IgniteSqlIntervalTypeNameSpec(intervalQualifier, s.end(this)), s.pos());
+ }
+}
+
+SqlDataTypeSpec UuidType() :
+{
+ final Span s;
+}
+{
+ <UUID> { s = span(); }
+ {
+ return new SqlDataTypeSpec(new SqlUserDefinedTypeNameSpec("UUID", s.end(this)), s.pos());
+ }
+}
+
+void TableElement(List<SqlNode> list) :
+{
+ final SqlDataTypeSpec type;
+ final boolean nullable;
+ final SqlNodeList columnList;
+ final Span s = Span.of();
+ final ColumnStrategy strategy;
+ final SqlNode dflt;
+ SqlIdentifier id = null;
+}
+{
+ id = SimpleIdentifier() type = DataTypeEx() nullable = NullableOptDefaultTrue()
+ (
+ <DEFAULT_> { s.add(this); } dflt = Literal() {
+ strategy = ColumnStrategy.DEFAULT;
+ }
+ |
+ {
+ dflt = null;
+ strategy = nullable ? ColumnStrategy.NULLABLE
+ : ColumnStrategy.NOT_NULLABLE;
+ }
+ )
+ [
+ <PRIMARY> { s.add(this); } <KEY> {
+ columnList = SqlNodeList.of(id);
+ list.add(SqlDdlNodes.primary(s.end(columnList), null, columnList));
+ }
+ ]
+ {
+ list.add(
+ SqlDdlNodes.column(s.add(id).end(this), id,
+ type.withNullable(nullable), dflt, strategy));
+ }
+|
+ [ <CONSTRAINT> { s.add(this); } id = SimpleIdentifier() ]
+ <PRIMARY> { s.add(this); } <KEY>
+ columnList = ParenthesizedSimpleIdentifierList() {
+ list.add(SqlDdlNodes.primary(s.end(columnList), id, columnList));
+ }
+}
+
+SqlNodeList TableElementList() :
+{
+ final Span s;
+ final List<SqlNode> list = new ArrayList<SqlNode>();
+}
+{
+ <LPAREN> { s = span(); }
+ TableElement(list)
+ (
+ <COMMA> TableElement(list)
+ )*
+ <RPAREN> {
+ return new SqlNodeList(list, s.end(this));
+ }
+}
+
+SqlCreate SqlCreateTable(Span s, boolean replace) :
+{
+ final boolean ifNotExists;
+ final SqlIdentifier id;
+ final SqlNodeList columnList;
+ final SqlNodeList optionList;
+ final SqlNode query;
+}
+{
+ <TABLE>
+ ifNotExists = IfNotExistsOpt()
+ id = CompoundIdentifier()
+ (
+ LOOKAHEAD(3)
+ columnList = TableElementList()
+ optionList = WithCreateTableOptionList()
+ { query = null; }
+ |
+ (
+ columnList = ParenthesizedSimpleIdentifierList()
+ |
+ { columnList = null; }
+ )
+ optionList = WithCreateTableOptionList()
+ <AS> { s.add(this); } query = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY)
+ )
+ {
+ return new IgniteSqlCreateTable(s.end(this), ifNotExists, id, columnList, query, optionList);
+ }
+}
+
+SqlNode IndexedColumn() :
+{
+ final Span s;
+ SqlNode col;
+}
+{
+ col = SimpleIdentifier()
+ (
+ <ASC>
+ | <DESC> {
+ col = SqlStdOperatorTable.DESC.createCall(getPos(), col);
+ }
+ )?
+ {
+ return col;
+ }
+}
+
+SqlNodeList IndexedColumnList() :
+{
+ final Span s;
+ final List<SqlNode> list = new ArrayList<SqlNode>();
+ SqlNode col = null;
+}
+{
+ <LPAREN> { s = span(); }
+ col = IndexedColumn() { list.add(col); }
+ (
+ <COMMA> col = IndexedColumn() { list.add(col); }
+ )*
+ <RPAREN> {
+ return new SqlNodeList(list, s.end(this));
+ }
+}
+
+SqlCreate SqlCreateIndex(Span s, boolean replace) :
+{
+ final boolean ifNotExists;
+ final SqlIdentifier idxId;
+ final SqlIdentifier tblId;
+ final SqlNodeList columnList;
+ SqlNumericLiteral parallel = null;
+ SqlNumericLiteral inlineSize = null;
+}
+{
+ <INDEX>
+ ifNotExists = IfNotExistsOpt()
+ idxId = SimpleIdentifier()
+ <ON>
+ tblId = CompoundIdentifier()
+ columnList = IndexedColumnList()
+ (
+ <PARALLEL> <UNSIGNED_INTEGER_LITERAL> {
+ if (parallel != null)
+ throw SqlUtil.newContextException(getPos(), IgniteResource.INSTANCE.optionAlreadyDefined("PARALLEL"));
+
+ parallel = SqlLiteral.createExactNumeric(token.image, getPos());
+ }
+ |
+ <INLINE_SIZE> <UNSIGNED_INTEGER_LITERAL> {
+ if (inlineSize != null)
+ throw SqlUtil.newContextException(getPos(), IgniteResource.INSTANCE.optionAlreadyDefined("INLINE_SIZE"));
+
+ inlineSize = SqlLiteral.createExactNumeric(token.image, getPos());
+ }
+ )*
+ {
+ return new IgniteSqlCreateIndex(s.end(this), ifNotExists, idxId, tblId, columnList, parallel, inlineSize);
+ }
+}
+
+boolean IfExistsOpt() :
+{
+}
+{
+ <IF> <EXISTS> { return true; }
+|
+ { return false; }
+}
+
+SqlDrop SqlDropTable(Span s, boolean replace) :
+{
+ final boolean ifExists;
+ final SqlIdentifier id;
+}
+{
+ <TABLE> ifExists = IfExistsOpt() id = CompoundIdentifier() {
+ return SqlDdlNodes.dropTable(s.end(this), ifExists, id);
+ }
+}
+
+SqlDrop SqlDropIndex(Span s, boolean replace) :
+{
+ final boolean ifExists;
+ final SqlIdentifier id;
+}
+{
+ <INDEX> ifExists = IfExistsOpt() id = CompoundIdentifier() {
+ return new IgniteSqlDropIndex(s.end(this), ifExists, id);
+ }
+}
+
+void InfixCast(List<Object> list, ExprContext exprContext, Span s) :
+{
+ final SqlDataTypeSpec dt;
+}
+{
+ <INFIX_CAST> {
+ checkNonQueryExpression(exprContext);
+ }
+ dt = DataTypeEx() {
+ list.add(
+ new SqlParserUtil.ToTreeListItem(SqlLibraryOperators.INFIX_CAST,
+ s.pos()));
+ list.add(dt);
+ }
+}
+
+SqlNodeList ColumnWithTypeList() :
+{
+ final Span s;
+ List<SqlNode> list = new ArrayList<SqlNode>();
+ SqlNode col;
+}
+{
+ <LPAREN> { s = span(); }
+ col = ColumnWithType() { list.add(col); }
+ (
+ <COMMA> col = ColumnWithType() { list.add(col); }
+ )*
+ <RPAREN> {
+ return new SqlNodeList(list, s.end(this));
+ }
+}
+
+SqlNode ColumnWithType() :
+{
+ SqlIdentifier id;
+ SqlDataTypeSpec type;
+ boolean nullable = true;
+ final Span s = Span.of();
+}
+{
+ id = SimpleIdentifier()
+ type = DataTypeEx()
+ [
+ <NOT> <NULL> {
+ nullable = false;
+ }
+ ]
+ {
+ return SqlDdlNodes.column(s.add(id).end(this), id, type.withNullable(nullable), null, null);
+ }
+}
+
+SqlNodeList ColumnWithTypeOrList() :
+{
+ SqlNode col;
+ SqlNodeList list;
+}
+{
+ col = ColumnWithType() { return new SqlNodeList(Collections.singletonList(col), col.getParserPosition()); }
+|
+ list = ColumnWithTypeList() { return list; }
+}
+
+SqlNode SqlAlterTable() :
+{
+ final Span s;
+ final boolean ifExists;
+ final SqlIdentifier id;
+ boolean colIgnoreErr;
+ SqlNode col;
+ SqlNodeList cols;
+}
+{
+ <ALTER> { s = span(); }
+ <TABLE> ifExists = IfExistsOpt() id = CompoundIdentifier()
+ (
+ <LOGGING> { return new IgniteSqlAlterTable(s.end(this), ifExists, id, true); }
+ |
+ <NOLOGGING> { return new IgniteSqlAlterTable(s.end(this), ifExists, id, false); }
+ |
+ <ADD> [<COLUMN>] colIgnoreErr = IfNotExistsOpt() cols = ColumnWithTypeOrList() {
+ return new IgniteSqlAlterTableAddColumn(s.end(this), ifExists, id, colIgnoreErr, cols);
+ }
+ |
+ <DROP> [<COLUMN>] colIgnoreErr = IfExistsOpt() cols = SimpleIdentifierOrList() {
+ return new IgniteSqlAlterTableDropColumn(s.end(this), ifExists, id, colIgnoreErr, cols);
+ }
+ )
+}
+
+SqlCreate SqlCreateUser(Span s, boolean replace) :
+{
+ final SqlIdentifier user;
+ final SqlNode password;
+}
+{
+ <USER> user = SimpleIdentifier()
+ <WITH> <PASSWORD> password = StringLiteral() {
+ return new IgniteSqlCreateUser(s.end(this), user, SqlLiteral.unchain(password));
+ }
+}
+
+SqlNode SqlAlterUser() :
+{
+ final Span s;
+ final SqlIdentifier user;
+ final SqlNode password;
+}
+{
+ <ALTER> { s = span(); } <USER> user = SimpleIdentifier()
+ <WITH> <PASSWORD> password = StringLiteral() {
+ return new IgniteSqlAlterUser(s.end(this), user, SqlLiteral.unchain(password));
+ }
+}
+
+SqlDrop SqlDropUser(Span s, boolean replace) :
+{
+ final SqlIdentifier user;
+}
+{
+ <USER> user = SimpleIdentifier() {
+ return new IgniteSqlDropUser(s.end(this), user);
+ }
+}
+
+<DEFAULT, DQID, BTID> TOKEN :
+{
+ < NEGATE: "!" >
+| < TILDE: "~" >
+}
+
+SqlNumericLiteral SignedIntegerLiteral() :
+{
+ final Span s;
+}
+{
+ <PLUS> <UNSIGNED_INTEGER_LITERAL> {
+ return SqlLiteral.createExactNumeric(token.image, getPos());
+ }
+|
+ <MINUS> { s = span(); } <UNSIGNED_INTEGER_LITERAL> {
+ return SqlLiteral.createNegative(SqlLiteral.createExactNumeric(token.image, getPos()), s.end(this));
+ }
+|
+ <UNSIGNED_INTEGER_LITERAL> {
+ return SqlLiteral.createExactNumeric(token.image, getPos());
+ }
+}
+
+SqlCharStringLiteral UuidLiteral():
+{
+ final Span s;
+ final String rawUuuid;
+}
+{
+ <QUOTED_STRING> {
+ String rawUuid = SqlParserUtil.parseString(token.image);
+ try {
+ java.util.UUID.fromString(rawUuid);
+ return SqlLiteral.createCharString(rawUuid, getPos());
+ }
+ catch (Exception e) {
+ throw SqlUtil.newContextException(getPos(), IgniteResource.INSTANCE.illegalUuid(rawUuid));
+ }
+ }
+}
+
+SqlCharStringLiteral IgniteUuidLiteral():
+{
+ final Span s;
+ final String rawUuuid;
+}
+{
+ <QUOTED_STRING> {
+ String rawUuid = SqlParserUtil.parseString(token.image);
+ try {
+ IgniteUuid.fromString(rawUuid);
+ return SqlLiteral.createCharString(rawUuid, getPos());
+ }
+ catch (Exception e) {
+ throw SqlUtil.newContextException(getPos(), IgniteResource.INSTANCE.illegalIgniteUuid(rawUuid));
+ }
+ }
+}
+
+SqlNode SqlKillScanQuery():
+{
+ final Span s;
+ final SqlCharStringLiteral originNodeId;
+ final SqlCharStringLiteral cacheName;
+ final SqlNumericLiteral queryId;
+}
+{
+ <KILL> { s = span(); } <SCAN>
+ originNodeId = UuidLiteral()
+ <QUOTED_STRING> {
+ cacheName = SqlLiteral.createCharString(SqlParserUtil.parseString(token.image), getPos());
+ }
+ queryId = SignedIntegerLiteral() {
+ return IgniteSqlKill.createScanQueryKill(s.end(this), originNodeId, cacheName, queryId);
+ }
+}
+
+SqlNode SqlKillContinuousQuery():
+{
+ final Span s;
+ final SqlCharStringLiteral originNodeId;
+ final SqlCharStringLiteral routineId;
+}
+{
+ <KILL> { s = span(); } <CONTINUOUS>
+ originNodeId = UuidLiteral()
+ routineId = UuidLiteral() {
+ return IgniteSqlKill.createContinuousQueryKill(s.end(this), originNodeId, routineId);
+ }
+}
+
+SqlNode SqlKillTransaction():
+{
+ final Span s;
+ final SqlCharStringLiteral xid;
+}
+{
+ <KILL> { s = span(); } <TRANSACTION>
+ xid = IgniteUuidLiteral() {
+ return IgniteSqlKill.createTransactionKill(s.end(this), xid);
+ }
+}
+
+SqlNode SqlKillService():
+{
+ final Span s;
+ final SqlCharStringLiteral srvName;
+}
+{
+ <KILL> { s = span(); } <SERVICE>
+ <QUOTED_STRING> {
+ srvName = SqlLiteral.createCharString(SqlParserUtil.parseString(token.image), getPos());
+ return IgniteSqlKill.createServiceKill(s.end(this), srvName);
+ }
+}
+
+SqlNode SqlKillComputeTask():
+{
+ final Span s;
+ final SqlCharStringLiteral sesId;
+}
+{
+ <KILL> { s = span(); } <COMPUTE>
+ sesId = IgniteUuidLiteral() {
+ return IgniteSqlKill.createComputeTaskKill(s.end(this), sesId);
+ }
+}
+
+boolean IsAsyncOpt() :
+{
+}
+{
+ <ASYNC> { return true; } | { return false; }
+}
+
+SqlNode SqlKillQuery():
+{
+ final Span s;
+ final boolean isAsync;
+}
+{
+ <KILL> { s = span(); } <QUERY>
+ isAsync= IsAsyncOpt()
+ <QUOTED_STRING> {
+ String rawQueryId = SqlParserUtil.parseString(token.image);
+ SqlCharStringLiteral queryIdLiteral = SqlLiteral.createCharString(rawQueryId, getPos());
+ Pair<UUID, Long> id = IgniteSqlKill.parseGlobalQueryId(rawQueryId);
+ if (id == null) {
+ throw SqlUtil.newContextException(getPos(), IgniteResource.INSTANCE.illegalGlobalQueryId(rawQueryId));
+ }
+ return IgniteSqlKill.createQueryKill(s.end(this), queryIdLiteral, id.getKey(), id.getValue(), isAsync);
+ }
+}
+
+SqlNode SqlCommitTransaction():
+{
+ final Span s;
+}
+{
+ <COMMIT> { s = span(); } (<TRANSACTION>)? {
+ return new IgniteSqlCommit(s.end(this));
+ }
+}
+
+SqlNode SqlRollbackTransaction():
+{
+ final Span s;
+}
+{
+ <ROLLBACK> { s = span(); } (<TRANSACTION>)? {
+ return new IgniteSqlRollback(s.end(this));
+ }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java b/modules/calcite/src/main/java/org/apache/calcite/plan/volcano/VolcanoUtils.java
similarity index 54%
copy from modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java
copy to modules/calcite/src/main/java/org/apache/calcite/plan/volcano/VolcanoUtils.java
index 38f3f67a..2b9293c 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java
+++ b/modules/calcite/src/main/java/org/apache/calcite/plan/volcano/VolcanoUtils.java
@@ -15,30 +15,17 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.processors.query.stat;
+package org.apache.calcite.plan.volcano;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Types of statistics width.
- */
-public enum StatisticsType {
- /** Statistics by some particular partition. */
- PARTITION,
-
- /** Statistics by some data node. */
- LOCAL;
-
- /** Enumerated values. */
- private static final StatisticsType[] VALUES = values();
+import org.apache.calcite.plan.RelOptCost;
+/** */
+public class VolcanoUtils {
/**
- * Efficiently gets enumerated value from its ordinal.
- *
- * @param ord Ordinal value.
- * @return Enumerated value or {@code null} if ordinal out of range.
+ * @param relSubset Subset.
+ * @return Cost of best known plan.
*/
- @Nullable public static StatisticsType fromOrdinal(int ord) {
- return ord >= 0 && ord < VALUES.length ? VALUES[ord] : null;
+ public static RelOptCost bestCost(RelSubset relSubset) {
+ return relSubset.bestCost;
}
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/command/SqlDropUserCommand.java b/modules/calcite/src/main/java/org/apache/ignite/calcite/CalciteQueryEngineConfiguration.java
similarity index 50%
copy from modules/core/src/main/java/org/apache/ignite/internal/sql/command/SqlDropUserCommand.java
copy to modules/calcite/src/main/java/org/apache/ignite/calcite/CalciteQueryEngineConfiguration.java
index e49d251..206cf24 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/sql/command/SqlDropUserCommand.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/calcite/CalciteQueryEngineConfiguration.java
@@ -15,45 +15,43 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.sql.command;
+package org.apache.ignite.calcite;
-import org.apache.ignite.internal.sql.SqlLexer;
-import org.apache.ignite.internal.sql.SqlParserUtils;
-import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.processors.query.QueryEngine;
+import org.apache.ignite.internal.processors.query.QueryEngineConfigurationEx;
+import org.apache.ignite.internal.processors.query.calcite.CalciteQueryProcessor;
+import org.apache.ignite.lang.IgniteExperimental;
/**
- * DROP USER command.
+ * Query engine configuration for Calcite-based query engine.
*/
-public class SqlDropUserCommand implements SqlCommand {
- /** User name. */
- private String userName;
+@IgniteExperimental
+public class CalciteQueryEngineConfiguration implements QueryEngineConfigurationEx {
+ /** Query engine name. */
+ public static final String ENGINE_NAME = "calcite";
+
+ /** */
+ private boolean isDflt;
/** {@inheritDoc} */
- @Override public String schemaName() {
- return null;
+ @Override public String engineName() {
+ return ENGINE_NAME;
}
/** {@inheritDoc} */
- @Override public void schemaName(String schemaName) {
- // No-op.
+ @Override public Class<? extends QueryEngine> engineClass() {
+ return CalciteQueryProcessor.class;
}
- /**
- * @return User name.
- */
- public String userName() {
- return userName;
+ /** {@inheritDoc} */
+ @Override public boolean isDefault() {
+ return isDflt;
}
/** {@inheritDoc} */
- @Override public SqlCommand parse(SqlLexer lex) {
- userName = SqlParserUtils.parseUsername(lex);
+ @Override public CalciteQueryEngineConfiguration setDefault(boolean isDflt) {
+ this.isDflt = isDflt;
return this;
}
-
- /** {@inheritDoc} */
- @Override public String toString() {
- return S.toString(SqlDropUserCommand.class, this);
- }
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/calcite/package-info.java b/modules/calcite/src/main/java/org/apache/ignite/calcite/package-info.java
new file mode 100644
index 0000000..3461ef1
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/calcite/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Contains Calcite-based query engine classes and interfaces.
+ */
+
+package org.apache.ignite.calcite;
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/CalciteQueryProcessor.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/CalciteQueryProcessor.java
new file mode 100644
index 0000000..beb3836
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/CalciteQueryProcessor.java
@@ -0,0 +1,442 @@
+/*
+ * 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.ignite.internal.processors.query.calcite;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import org.apache.calcite.DataContexts;
+import org.apache.calcite.config.Lex;
+import org.apache.calcite.config.NullCollation;
+import org.apache.calcite.plan.Contexts;
+import org.apache.calcite.plan.ConventionTraitDef;
+import org.apache.calcite.plan.RelTraitDef;
+import org.apache.calcite.rel.RelCollationTraitDef;
+import org.apache.calcite.rel.core.Aggregate;
+import org.apache.calcite.rel.hint.HintStrategyTable;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlNodeList;
+import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql.util.SqlOperatorTables;
+import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.sql2rel.SqlToRelConverter;
+import org.apache.calcite.tools.FrameworkConfig;
+import org.apache.calcite.tools.Frameworks;
+import org.apache.ignite.SystemProperty;
+import org.apache.ignite.cache.query.FieldsQueryCursor;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.GridProcessorAdapter;
+import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
+import org.apache.ignite.internal.processors.failure.FailureProcessor;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.processors.query.QueryContext;
+import org.apache.ignite.internal.processors.query.QueryEngine;
+import org.apache.ignite.internal.processors.query.RunningQuery;
+import org.apache.ignite.internal.processors.query.calcite.exec.ArrayRowHandler;
+import org.apache.ignite.internal.processors.query.calcite.exec.ExchangeService;
+import org.apache.ignite.internal.processors.query.calcite.exec.ExchangeServiceImpl;
+import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionService;
+import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionServiceImpl;
+import org.apache.ignite.internal.processors.query.calcite.exec.MailboxRegistry;
+import org.apache.ignite.internal.processors.query.calcite.exec.MailboxRegistryImpl;
+import org.apache.ignite.internal.processors.query.calcite.exec.QueryTaskExecutor;
+import org.apache.ignite.internal.processors.query.calcite.exec.QueryTaskExecutorImpl;
+import org.apache.ignite.internal.processors.query.calcite.exec.exp.RexExecutorImpl;
+import org.apache.ignite.internal.processors.query.calcite.message.MessageService;
+import org.apache.ignite.internal.processors.query.calcite.message.MessageServiceImpl;
+import org.apache.ignite.internal.processors.query.calcite.metadata.AffinityService;
+import org.apache.ignite.internal.processors.query.calcite.metadata.AffinityServiceImpl;
+import org.apache.ignite.internal.processors.query.calcite.metadata.MappingService;
+import org.apache.ignite.internal.processors.query.calcite.metadata.MappingServiceImpl;
+import org.apache.ignite.internal.processors.query.calcite.metadata.cost.IgniteCostFactory;
+import org.apache.ignite.internal.processors.query.calcite.prepare.CacheKey;
+import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteConvertletTable;
+import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteTypeCoercion;
+import org.apache.ignite.internal.processors.query.calcite.prepare.PrepareServiceImpl;
+import org.apache.ignite.internal.processors.query.calcite.prepare.QueryPlan;
+import org.apache.ignite.internal.processors.query.calcite.prepare.QueryPlanCache;
+import org.apache.ignite.internal.processors.query.calcite.prepare.QueryPlanCacheImpl;
+import org.apache.ignite.internal.processors.query.calcite.schema.SchemaHolder;
+import org.apache.ignite.internal.processors.query.calcite.schema.SchemaHolderImpl;
+import org.apache.ignite.internal.processors.query.calcite.sql.IgniteSqlConformance;
+import org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteOwnSqlOperatorTable;
+import org.apache.ignite.internal.processors.query.calcite.sql.fun.IgniteStdSqlOperatorTable;
+import org.apache.ignite.internal.processors.query.calcite.sql.generated.IgniteSqlParserImpl;
+import org.apache.ignite.internal.processors.query.calcite.trait.CorrelationTraitDef;
+import org.apache.ignite.internal.processors.query.calcite.trait.DistributionTraitDef;
+import org.apache.ignite.internal.processors.query.calcite.trait.RewindabilityTraitDef;
+import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeSystem;
+import org.apache.ignite.internal.processors.query.calcite.util.Commons;
+import org.apache.ignite.internal.processors.query.calcite.util.LifecycleAware;
+import org.apache.ignite.internal.processors.query.calcite.util.Service;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.IgniteSystemProperties.getLong;
+
+/** */
+public class CalciteQueryProcessor extends GridProcessorAdapter implements QueryEngine {
+ /**
+ * Default planner timeout, in ms.
+ */
+ private static final long DFLT_IGNITE_CALCITE_PLANNER_TIMEOUT = 15000;
+
+ /**
+ * Planner timeout property name.
+ */
+ @SystemProperty(value = "Timeout of calcite based sql engine's planner, in ms", type = Long.class,
+ defaults = "" + DFLT_IGNITE_CALCITE_PLANNER_TIMEOUT)
+ public static final String IGNITE_CALCITE_PLANNER_TIMEOUT = "IGNITE_CALCITE_PLANNER_TIMEOUT";
+
+ /** */
+ public static final FrameworkConfig FRAMEWORK_CONFIG = Frameworks.newConfigBuilder()
+ .executor(new RexExecutorImpl(DataContexts.EMPTY))
+ .sqlToRelConverterConfig(SqlToRelConverter.config()
+ .withTrimUnusedFields(true)
+ // currently SqlToRelConverter creates not optimal plan for both optimization and execution
+ // so it's better to disable such rewriting right now
+ // TODO: remove this after IGNITE-14277
+ .withInSubQueryThreshold(Integer.MAX_VALUE)
+ .withDecorrelationEnabled(true)
+ .withExpand(false)
+ .withHintStrategyTable(
+ HintStrategyTable.builder()
+ .hintStrategy("DISABLE_RULE", (hint, rel) -> true)
+ .hintStrategy("EXPAND_DISTINCT_AGG", (hint, rel) -> rel instanceof Aggregate)
+ // QUERY_ENGINE hint preprocessed by regexp, but to avoid warnings should be also in HintStrategyTable.
+ .hintStrategy("QUERY_ENGINE", (hint, rel) -> true)
+ .build()
+ )
+ )
+ .convertletTable(IgniteConvertletTable.INSTANCE)
+ .parserConfig(
+ SqlParser.config()
+ .withParserFactory(IgniteSqlParserImpl.FACTORY)
+ .withLex(Lex.ORACLE)
+ .withConformance(IgniteSqlConformance.INSTANCE))
+ .sqlValidatorConfig(SqlValidator.Config.DEFAULT
+ .withIdentifierExpansion(true)
+ .withDefaultNullCollation(NullCollation.LOW)
+ .withSqlConformance(IgniteSqlConformance.INSTANCE)
+ .withTypeCoercionFactory(IgniteTypeCoercion::new))
+ // Dialects support.
+ .operatorTable(SqlOperatorTables.chain(IgniteStdSqlOperatorTable.INSTANCE, IgniteOwnSqlOperatorTable.instance()))
+ // Context provides a way to store data within the planner session that can be accessed in planner rules.
+ .context(Contexts.empty())
+ // Custom cost factory to use during optimization
+ .costFactory(new IgniteCostFactory())
+ .typeSystem(IgniteTypeSystem.INSTANCE)
+ .traitDefs(new RelTraitDef<?>[] {
+ ConventionTraitDef.INSTANCE,
+ RelCollationTraitDef.INSTANCE,
+ DistributionTraitDef.INSTANCE,
+ RewindabilityTraitDef.INSTANCE,
+ CorrelationTraitDef.INSTANCE,
+ })
+ .build();
+
+ /** Query planner timeout. */
+ private final long queryPlannerTimeout = getLong(IGNITE_CALCITE_PLANNER_TIMEOUT,
+ DFLT_IGNITE_CALCITE_PLANNER_TIMEOUT);
+
+ /** */
+ private final QueryPlanCache qryPlanCache;
+
+ /** */
+ private final QueryTaskExecutor taskExecutor;
+
+ /** */
+ private final FailureProcessor failureProcessor;
+
+ /** */
+ private final AffinityService partSvc;
+
+ /** */
+ private final SchemaHolder schemaHolder;
+
+ /** */
+ private final MessageService msgSvc;
+
+ /** */
+ private final ExchangeService exchangeSvc;
+
+ /** */
+ private final MappingService mappingSvc;
+
+ /** */
+ private final MailboxRegistry mailboxRegistry;
+
+ /** */
+ private final ExecutionService<Object[]> executionSvc;
+
+ /** */
+ private final PrepareServiceImpl prepareSvc;
+
+ /** */
+ private final QueryRegistry qryReg;
+
+ /**
+ * @param ctx Kernal context.
+ */
+ public CalciteQueryProcessor(GridKernalContext ctx) {
+ super(ctx);
+
+ failureProcessor = ctx.failure();
+ schemaHolder = new SchemaHolderImpl(ctx);
+ qryPlanCache = new QueryPlanCacheImpl(ctx);
+ mailboxRegistry = new MailboxRegistryImpl(ctx);
+ taskExecutor = new QueryTaskExecutorImpl(ctx);
+ executionSvc = new ExecutionServiceImpl<>(ctx, ArrayRowHandler.INSTANCE);
+ partSvc = new AffinityServiceImpl(ctx);
+ msgSvc = new MessageServiceImpl(ctx);
+ mappingSvc = new MappingServiceImpl(ctx);
+ exchangeSvc = new ExchangeServiceImpl(ctx);
+ prepareSvc = new PrepareServiceImpl(ctx);
+ qryReg = new QueryRegistryImpl(ctx);
+ }
+
+ /**
+ * @return Affinity service.
+ */
+ public AffinityService affinityService() {
+ return partSvc;
+ }
+
+ /**
+ * @return Query cache.
+ */
+ public QueryPlanCache queryPlanCache() {
+ return qryPlanCache;
+ }
+
+ /**
+ * @return Task executor.
+ */
+ public QueryTaskExecutor taskExecutor() {
+ return taskExecutor;
+ }
+
+ /**
+ * @return Schema holder.
+ */
+ public SchemaHolder schemaHolder() {
+ return schemaHolder;
+ }
+
+ /**
+ * @return Message service.
+ */
+ public MessageService messageService() {
+ return msgSvc;
+ }
+
+ /**
+ * @return Mapping service.
+ */
+ public MappingService mappingService() {
+ return mappingSvc;
+ }
+
+ /**
+ * @return Exchange service.
+ */
+ public ExchangeService exchangeService() {
+ return exchangeSvc;
+ }
+
+ /**
+ * @return Mailbox registry.
+ */
+ public MailboxRegistry mailboxRegistry() {
+ return mailboxRegistry;
+ }
+
+ /**
+ * @return Failure processor.
+ */
+ public FailureProcessor failureProcessor() {
+ return failureProcessor;
+ }
+
+ /** */
+ public PrepareServiceImpl prepareService() {
+ return prepareSvc;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void start() {
+ onStart(ctx,
+ executionSvc,
+ mailboxRegistry,
+ partSvc,
+ schemaHolder,
+ msgSvc,
+ taskExecutor,
+ mappingSvc,
+ qryPlanCache,
+ exchangeSvc,
+ qryReg
+ );
+ }
+
+ /** {@inheritDoc} */
+ @Override public void stop(boolean cancel) {
+ onStop(
+ qryReg,
+ executionSvc,
+ mailboxRegistry,
+ partSvc,
+ schemaHolder,
+ msgSvc,
+ taskExecutor,
+ mappingSvc,
+ qryPlanCache,
+ exchangeSvc
+ );
+ }
+
+ /** {@inheritDoc} */
+ @Override public List<FieldsQueryCursor<List<?>>> query(
+ @Nullable QueryContext qryCtx,
+ @Nullable String schemaName,
+ String sql,
+ Object... params
+ ) throws IgniteSQLException {
+ SchemaPlus schema = schemaHolder.schema(schemaName);
+
+ assert schema != null : "Schema not found: " + schemaName;
+
+ QueryPlan plan = queryPlanCache().queryPlan(new CacheKey(schema.getName(), sql));
+
+ if (plan != null) {
+ RootQuery<Object[]> qry = new RootQuery<>(
+ sql,
+ schema,
+ params,
+ qryCtx,
+ exchangeSvc,
+ (q) -> qryReg.unregister(q.id()),
+ log,
+ queryPlannerTimeout
+ );
+
+ qryReg.register(qry);
+
+ try {
+ return Collections.singletonList(executionSvc.executePlan(
+ qry,
+ plan
+ ));
+ }
+ catch (Exception e) {
+ boolean isCanceled = qry.isCancelled();
+
+ qry.cancel();
+
+ qryReg.unregister(qry.id());
+
+ if (isCanceled)
+ throw new IgniteSQLException("The query was cancelled while planning", IgniteQueryErrorCode.QUERY_CANCELED, e);
+ else
+ throw e;
+
+ }
+ }
+
+ SqlNodeList qryList = Commons.parse(sql, FRAMEWORK_CONFIG.getParserConfig());
+ List<FieldsQueryCursor<List<?>>> cursors = new ArrayList<>(qryList.size());
+
+ List<RootQuery<Object[]>> qrys = new ArrayList<>(qryList.size());
+
+ for (final SqlNode sqlNode: qryList) {
+ RootQuery<Object[]> qry = new RootQuery<>(
+ sqlNode.toString(),
+ schemaHolder.schema(schemaName), // Update schema for each query in multiple statements.
+ params,
+ qryCtx,
+ exchangeSvc,
+ (q) -> qryReg.unregister(q.id()),
+ log,
+ queryPlannerTimeout
+ );
+
+ qrys.add(qry);
+
+ qryReg.register(qry);
+
+ try {
+ if (qryList.size() == 1) {
+ plan = queryPlanCache().queryPlan(
+ new CacheKey(schemaName, sql), // Use source SQL to avoid redundant parsing next time.
+ () -> prepareSvc.prepareSingle(sqlNode, qry.planningContext()));
+ }
+ else
+ plan = prepareSvc.prepareSingle(sqlNode, qry.planningContext());
+
+ cursors.add(executionSvc.executePlan(qry, plan));
+ }
+ catch (Exception e) {
+ boolean isCanceled = qry.isCancelled();
+
+ qrys.forEach(RootQuery::cancel);
+
+ qryReg.unregister(qry.id());
+
+ if (isCanceled)
+ throw new IgniteSQLException("The query was cancelled while planning", IgniteQueryErrorCode.QUERY_CANCELED, e);
+ else
+ throw e;
+ }
+ }
+
+ return cursors;
+ }
+
+ /** */
+ private void onStart(GridKernalContext ctx, Service... services) {
+ for (Service service : services) {
+ if (service instanceof LifecycleAware)
+ ((LifecycleAware)service).onStart(ctx);
+ }
+ }
+
+ /** */
+ private void onStop(Service... services) {
+ for (Service service : services) {
+ if (service instanceof LifecycleAware)
+ ((LifecycleAware)service).onStop();
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public RunningQuery runningQuery(UUID id) {
+ return qryReg.query(id);
+ }
+
+ /** {@inheritDoc} */
+ @Override public Collection<? extends RunningQuery> runningQueries() {
+ return qryReg.runningQueries();
+ }
+
+ /** */
+ public QueryRegistry queryRegistry() {
+ return qryReg;
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/Query.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/Query.java
new file mode 100644
index 0000000..09be27c
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/Query.java
@@ -0,0 +1,242 @@
+/*
+ * 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.ignite.internal.processors.query.calcite;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
+import org.apache.ignite.internal.processors.query.GridQueryCancel;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.processors.query.QueryState;
+import org.apache.ignite.internal.processors.query.RunningQuery;
+import org.apache.ignite.internal.processors.query.calcite.exec.ExchangeService;
+import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionCancelledException;
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+/** */
+public class Query<RowT> implements RunningQuery {
+ /** */
+ private final UUID initNodeId;
+
+ /** */
+ private final UUID id;
+
+ /** */
+ protected final Object mux = new Object();
+
+ /** */
+ protected final Set<RunningFragment<RowT>> fragments;
+
+ /** */
+ protected final GridQueryCancel cancel;
+
+ /** */
+ protected final Consumer<Query<RowT>> unregister;
+
+ /** */
+ protected volatile QueryState state = QueryState.INITED;
+
+ /** */
+ protected final ExchangeService exch;
+
+ /** */
+ protected final int totalFragmentsCnt;
+
+ /** */
+ protected final AtomicInteger finishedFragmentsCnt = new AtomicInteger();
+
+ /** */
+ protected final Set<Long> initNodeStartedExchanges = new HashSet<>();
+
+ /** Logger. */
+ protected final IgniteLogger log;
+
+ /** */
+ public Query(
+ UUID id,
+ UUID initNodeId,
+ GridQueryCancel cancel,
+ ExchangeService exch,
+ Consumer<Query<RowT>> unregister,
+ IgniteLogger log,
+ int totalFragmentsCnt
+ ) {
+ this.id = id;
+ this.unregister = unregister;
+ this.initNodeId = initNodeId;
+ this.exch = exch;
+ this.log = log;
+
+ this.cancel = cancel != null ? cancel : new GridQueryCancel();
+
+ fragments = Collections.newSetFromMap(new ConcurrentHashMap<>());
+ this.totalFragmentsCnt = totalFragmentsCnt;
+ }
+
+ /** {@inheritDoc} */
+ @Override public UUID id() {
+ return id;
+ }
+
+ /** {@inheritDoc} */
+ @Override public QueryState state() {
+ return state;
+ }
+
+ /** */
+ public UUID initiatorNodeId() {
+ return initNodeId;
+ }
+
+ /** */
+ protected void tryClose() {
+ List<RunningFragment<RowT>> fragments = new ArrayList<>(this.fragments);
+
+ AtomicInteger cntDown = new AtomicInteger(fragments.size());
+
+ for (RunningFragment<RowT> frag : fragments) {
+ frag.context().execute(() -> {
+ frag.root().close();
+ frag.context().cancel();
+
+ if (cntDown.decrementAndGet() == 0)
+ unregister.accept(this);
+
+ }, frag.root()::onError);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void cancel() {
+ synchronized (mux) {
+ if (state == QueryState.CLOSED)
+ return;
+
+ if (state == QueryState.INITED) {
+ state = QueryState.CLOSING;
+
+ try {
+ exch.closeQuery(initNodeId, id);
+
+ return;
+ }
+ catch (IgniteCheckedException e) {
+ log.warning("Cannot send cancel request to query initiator", e);
+ }
+ }
+
+ if (state == QueryState.EXECUTING || state == QueryState.CLOSING)
+ state = QueryState.CLOSED;
+ }
+
+ for (RunningFragment<RowT> frag : fragments)
+ frag.context().execute(() -> frag.root().onError(new ExecutionCancelledException()), frag.root()::onError);
+
+ tryClose();
+ }
+
+ /** */
+ public void addFragment(RunningFragment<RowT> f) {
+ synchronized (mux) {
+ if (state == QueryState.INITED)
+ state = QueryState.EXECUTING;
+
+ if (state == QueryState.CLOSING || state == QueryState.CLOSED) {
+ throw new IgniteSQLException(
+ "The query was cancelled",
+ IgniteQueryErrorCode.QUERY_CANCELED,
+ new ExecutionCancelledException()
+ );
+ }
+
+ fragments.add(f);
+ }
+ }
+
+ /** */
+ public boolean isCancelled() {
+ return cancel.isCanceled();
+ }
+
+ /** */
+ public void onNodeLeft(UUID nodeId) {
+ if (initNodeId.equals(nodeId))
+ cancel();
+ }
+
+ /**
+ * Callback after the first batch of the query fragment from the node is received.
+ */
+ public void onInboundExchangeStarted(UUID nodeId, long exchangeId) {
+ // No-op.
+ }
+
+ /**
+ * Callback after the last batch of the query fragment from the node is processed.
+ */
+ public void onInboundExchangeFinished(UUID nodeId, long exchangeId) {
+ // No-op.
+ }
+
+ /**
+ * Callback after the first batch of the query fragment from the node is sent.
+ */
+ public void onOutboundExchangeStarted(UUID nodeId, long exchangeId) {
+ if (initNodeId.equals(nodeId))
+ initNodeStartedExchanges.add(exchangeId);
+ }
+
+ /**
+ * Callback after the last batch of the query fragment is sent to all nodes.
+ */
+ public void onOutboundExchangeFinished(long exchangeId) {
+ if (finishedFragmentsCnt.incrementAndGet() == totalFragmentsCnt) {
+ QueryState state0;
+
+ synchronized (mux) {
+ state0 = state;
+
+ if (state0 == QueryState.EXECUTING)
+ state = QueryState.CLOSED;
+ }
+
+ if (state0 == QueryState.EXECUTING)
+ tryClose();
+ }
+ }
+
+ /** */
+ public boolean isExchangeWithInitNodeStarted(long fragmentId) {
+ // On remote node exchange ID is the same as fragment ID.
+ return initNodeStartedExchanges.contains(fragmentId);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(Query.class, this, "state", state, "fragments", fragments);
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/QueryRegistry.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/QueryRegistry.java
new file mode 100644
index 0000000..f3a411d
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/QueryRegistry.java
@@ -0,0 +1,54 @@
+/*
+ * 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.ignite.internal.processors.query.calcite;
+
+import java.util.Collection;
+import java.util.UUID;
+import org.apache.ignite.internal.processors.query.RunningQuery;
+import org.apache.ignite.internal.processors.query.calcite.util.Service;
+
+/**
+ * Registry of the running queries.
+ */
+public interface QueryRegistry extends Service {
+ /**
+ * Register the query or return the existing one with the same identifier.
+ *
+ * @param qry Query to register.
+ * @return Registered query.
+ */
+ RunningQuery register(RunningQuery qry);
+
+ /**
+ * Lookup query by identifier.
+ *
+ * @param id Query identified.
+ * @return Registered query or {@code null} if the query with specified identifier isn't found.
+ */
+ RunningQuery query(UUID id);
+
+ /**
+ * Unregister query by identifier.
+ *
+ * @param id Query identifier.
+ */
+ void unregister(UUID id);
+
+ /** */
+ Collection<? extends RunningQuery> runningQueries();
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/QueryRegistryImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/QueryRegistryImpl.java
new file mode 100644
index 0000000..58c5df1
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/QueryRegistryImpl.java
@@ -0,0 +1,108 @@
+/*
+ * 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.ignite.internal.processors.query.calcite;
+
+import java.util.Collection;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.apache.ignite.cache.query.QueryCancelledException;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.cache.query.GridCacheQueryType;
+import org.apache.ignite.internal.processors.query.GridQueryCancel;
+import org.apache.ignite.internal.processors.query.RunningQuery;
+import org.apache.ignite.internal.processors.query.RunningQueryManager;
+import org.apache.ignite.internal.processors.query.calcite.util.AbstractService;
+import org.apache.ignite.internal.util.IgniteUtils;
+
+/**
+ * Registry of the running queries.
+ */
+public class QueryRegistryImpl extends AbstractService implements QueryRegistry {
+ /** */
+ private final ConcurrentMap<UUID, RunningQuery> runningQrys = new ConcurrentHashMap<>();
+
+ /** */
+ protected final GridKernalContext kctx;
+
+ /** */
+ public QueryRegistryImpl(GridKernalContext ctx) {
+ super(ctx);
+
+ kctx = ctx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public RunningQuery register(RunningQuery qry) {
+ return runningQrys.computeIfAbsent(qry.id(), k -> {
+ if (!(qry instanceof RootQuery))
+ return qry;
+
+ RootQuery<?> rootQry = (RootQuery<?>)qry;
+
+ RunningQueryManager qryMgr = kctx.query().runningQueryManager();
+
+ SqlFieldsQuery fieldsQry = rootQry.context().unwrap(SqlFieldsQuery.class);
+
+ String initiatorId = fieldsQry != null ? fieldsQry.getQueryInitiatorId() : null;
+
+ long locId = qryMgr.register(rootQry.sql(), GridCacheQueryType.SQL_FIELDS, rootQry.context().schemaName(),
+ false, createCancelToken(qry), initiatorId);
+
+ rootQry.localQueryId(locId);
+
+ return qry;
+ });
+ }
+
+ /** {@inheritDoc} */
+ @Override public RunningQuery query(UUID id) {
+ return runningQrys.get(id);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void unregister(UUID id) {
+ RunningQuery val = runningQrys.remove(id);
+ if (val instanceof RootQuery<?>)
+ kctx.query().runningQueryManager().unregister(((RootQuery<?>)val).localQueryId(), null);
+ }
+
+ /** {@inheritDoc} */
+ @Override public Collection<? extends RunningQuery> runningQueries() {
+ return runningQrys.values();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void tearDown() {
+ runningQrys.values().forEach(q -> IgniteUtils.close(q::cancel, log));
+ runningQrys.clear();
+ }
+
+ /** */
+ private static GridQueryCancel createCancelToken(RunningQuery qry) {
+ GridQueryCancel token = new GridQueryCancel();
+ try {
+ token.add(qry::cancel);
+ }
+ catch (QueryCancelledException ignore) {
+ // Ignore, since it is impossible;
+ }
+ return token;
+ }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/KillQueryRun.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RemoteFragmentKey.java
similarity index 50%
copy from modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/KillQueryRun.java
copy to modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RemoteFragmentKey.java
index a6c0565..a2a0c64 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/KillQueryRun.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RemoteFragmentKey.java
@@ -13,59 +13,54 @@
* 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.ignite.internal.processors.query.h2;
+package org.apache.ignite.internal.processors.query.calcite;
import java.util.UUID;
-import org.apache.ignite.internal.util.future.GridFutureAdapter;
-/**
- * Kill Query run context.
- */
-class KillQueryRun {
- /** Node id. */
+/** */
+final class RemoteFragmentKey {
+ /** */
private final UUID nodeId;
- /** Node query id. */
- private final long nodeQryId;
-
- /** Cancellation query future. */
- private final GridFutureAdapter<String> cancelFut;
-
- /**
- * Constructor.
- *
- * @param nodeId Node id.
- * @param cancelFut Cancellation query future.
- */
- public KillQueryRun(UUID nodeId, long nodeQryId, GridFutureAdapter<String> cancelFut) {
- assert nodeId != null;
+ /** */
+ private final long fragmentId;
+ /** */
+ RemoteFragmentKey(UUID nodeId, long fragmentId) {
this.nodeId = nodeId;
- this.nodeQryId = nodeQryId;
- this.cancelFut = cancelFut;
+ this.fragmentId = fragmentId;
}
- /**
- * @return Node id.
- */
+ /** */
public UUID nodeId() {
return nodeId;
}
- /**
- * @return Node query id.
- */
- public long nodeQryId() {
- return nodeQryId;
+ /** */
+ public long fragmentId() {
+ return fragmentId;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ RemoteFragmentKey that = (RemoteFragmentKey)o;
+
+ if (fragmentId != that.fragmentId)
+ return false;
+ return nodeId.equals(that.nodeId);
}
- /**
- * @return Cancellation query future.
- */
- public GridFutureAdapter<String> cancelFuture() {
- return cancelFut;
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ int res = nodeId.hashCode();
+ res = 31 * res + (int)(fragmentId ^ (fragmentId >>> 32));
+ return res;
}
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RootQuery.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RootQuery.java
new file mode 100644
index 0000000..1b81f63
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RootQuery.java
@@ -0,0 +1,405 @@
+/*
+ * 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.ignite.internal.processors.query.calcite;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import org.apache.calcite.plan.Context;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.tools.Frameworks;
+import org.apache.calcite.util.CancelFlag;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.cache.query.QueryCancelledException;
+import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
+import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
+import org.apache.ignite.internal.processors.query.GridQueryCancel;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.processors.query.QueryContext;
+import org.apache.ignite.internal.processors.query.QueryState;
+import org.apache.ignite.internal.processors.query.calcite.exec.ExchangeService;
+import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Node;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.RootNode;
+import org.apache.ignite.internal.processors.query.calcite.prepare.BaseQueryContext;
+import org.apache.ignite.internal.processors.query.calcite.prepare.Fragment;
+import org.apache.ignite.internal.processors.query.calcite.prepare.MultiStepPlan;
+import org.apache.ignite.internal.processors.query.calcite.prepare.PlanningContext;
+import org.apache.ignite.internal.processors.query.calcite.util.Commons;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+import static org.apache.ignite.internal.processors.query.calcite.CalciteQueryProcessor.FRAMEWORK_CONFIG;
+
+/**
+ * The RootQuery is created on the query initiator (originator) node as the first step of a query run;
+ * It contains the information about query state, contexts, remote fragments;
+ * It provides 'cancel' functionality for running query like a base query class.
+ */
+public class RootQuery<RowT> extends Query<RowT> {
+ /** SQL query. */
+ private final String sql;
+
+ /** Parameters. */
+ private final Object[] params;
+
+ /** Remote nodes unfinished fragments count. AtomicInteger used just as int holder, there is no concurrency here. */
+ private final Map<UUID, AtomicInteger> remoteFragments;
+
+ /** Node to fragment. */
+ private final Set<RemoteFragmentKey> waiting;
+
+ /** */
+ private volatile RootNode<RowT> root;
+
+ /** */
+ private volatile PlanningContext pctx;
+
+ /** */
+ private final BaseQueryContext ctx;
+
+ /** */
+ private final long plannerTimeout;
+
+ /** */
+ private volatile long locQryId;
+
+ /** */
+ public RootQuery(
+ String sql,
+ SchemaPlus schema,
+ Object[] params,
+ QueryContext qryCtx,
+ ExchangeService exch,
+ Consumer<Query<RowT>> unregister,
+ IgniteLogger log,
+ long plannerTimeout
+ ) {
+ super(
+ UUID.randomUUID(),
+ null,
+ qryCtx != null ? qryCtx.unwrap(GridQueryCancel.class) : null,
+ exch,
+ unregister,
+ log,
+ 0 // Total fragments count not used for RootQuery.
+ );
+
+ this.sql = sql;
+ this.params = params;
+
+ remoteFragments = new HashMap<>();
+ waiting = new HashSet<>();
+
+ this.plannerTimeout = plannerTimeout;
+
+ Context parent = Commons.convert(qryCtx);
+
+ ctx = BaseQueryContext.builder()
+ .parentContext(parent)
+ .frameworkConfig(
+ Frameworks.newConfigBuilder(FRAMEWORK_CONFIG)
+ .defaultSchema(schema)
+ .build()
+ )
+ .logger(log)
+ .build();
+ }
+
+ /**
+ * Creates the new root that inherits the query parameters from {@code this} query.
+ * Is used to execute DML query immediately after (inside) DDL.
+ * e.g.:
+ * CREATE TABLE MY_TABLE AS SELECT ... FROM ...;
+ *
+ * @param schema new schema.
+ */
+ public RootQuery<RowT> childQuery(SchemaPlus schema) {
+ return new RootQuery<>(sql, schema, params, QueryContext.of(cancel), exch, unregister, log, plannerTimeout);
+ }
+
+ /** */
+ public BaseQueryContext context() {
+ return ctx;
+ }
+
+ /** */
+ public String sql() {
+ return sql;
+ }
+
+ /** */
+ public Object[] parameters() {
+ return params;
+ }
+
+ /**
+ * Starts maping phase for the query.
+ */
+ public void mapping() {
+ synchronized (mux) {
+ if (state == QueryState.CLOSED) {
+ throw new IgniteSQLException(
+ "The query was cancelled while executing.",
+ IgniteQueryErrorCode.QUERY_CANCELED
+ );
+ }
+
+ state = QueryState.MAPPING;
+ }
+ }
+
+ /**
+ * Starts execution phase for the query and setup remote fragments.
+ */
+ public void run(ExecutionContext<RowT> ctx, MultiStepPlan plan, Node<RowT> root) {
+ synchronized (mux) {
+ if (state == QueryState.CLOSED) {
+ throw new IgniteSQLException(
+ "The query was cancelled while executing.",
+ IgniteQueryErrorCode.QUERY_CANCELED
+ );
+ }
+
+ RootNode<RowT> rootNode = new RootNode<>(ctx, plan.fieldsMetadata().rowType(), this::tryClose);
+ rootNode.register(root);
+
+ addFragment(new RunningFragment<>(F.first(plan.fragments()).root(), rootNode, ctx));
+
+ this.root = rootNode;
+
+ for (int i = 1; i < plan.fragments().size(); i++) {
+ Fragment fragment = plan.fragments().get(i);
+ List<UUID> nodes = plan.mapping(fragment).nodeIds();
+
+ nodes.forEach(n -> remoteFragments.compute(n, (id, cnt) -> {
+ if (cnt == null)
+ return new AtomicInteger(1);
+ else {
+ cnt.incrementAndGet();
+
+ return cnt;
+ }
+ }));
+
+ for (UUID node : nodes)
+ waiting.add(new RemoteFragmentKey(node, fragment.fragmentId()));
+ }
+
+ state = QueryState.EXECUTING;
+ }
+ }
+
+ /**
+ * Can be called multiple times after receive each error
+ * at {@link #onResponse(RemoteFragmentKey, Throwable)}.
+ */
+ @Override protected void tryClose() {
+ QueryState state0 = null;
+
+ synchronized (mux) {
+ if (state == QueryState.CLOSED)
+ return;
+
+ if (state == QueryState.INITED || state == QueryState.PLANNING || state == QueryState.MAPPING) {
+ state = QueryState.CLOSED;
+
+ return;
+ }
+
+ if (state == QueryState.EXECUTING) {
+ state0 = state = QueryState.CLOSING;
+
+ root.closeInternal();
+ }
+
+ if (state == QueryState.CLOSING && waiting.isEmpty())
+ state0 = state = QueryState.CLOSED;
+ }
+
+ if (state0 == QueryState.CLOSED) {
+ try {
+ IgniteException wrpEx = null;
+
+ for (Map.Entry<UUID, AtomicInteger> entry : remoteFragments.entrySet()) {
+ try {
+ // Don't send close message if all remote fragments are finished (query is self-closed on the
+ // remote node in this case).
+ if (!entry.getKey().equals(root.context().localNodeId()) && entry.getValue().get() > 0)
+ exch.closeQuery(entry.getKey(), id());
+ }
+ catch (IgniteCheckedException e) {
+ if (wrpEx == null)
+ wrpEx = new IgniteException("Failed to send cancel message. [nodeId=" + entry.getKey() + ']', e);
+ else
+ wrpEx.addSuppressed(e);
+ }
+ }
+
+ if (wrpEx != null)
+ log.warning("An exception occures during the query cancel", wrpEx);
+ }
+ finally {
+ super.tryClose();
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void cancel() {
+ cancel.cancel();
+
+ tryClose();
+ }
+
+ /** */
+ public PlanningContext planningContext() {
+ synchronized (mux) {
+ if (state == QueryState.CLOSED || state == QueryState.CLOSING) {
+ throw new IgniteSQLException(
+ "The query was cancelled while executing.",
+ IgniteQueryErrorCode.QUERY_CANCELED
+ );
+ }
+
+ if (state == QueryState.EXECUTING || state == QueryState.MAPPING) {
+ throw new IgniteSQLException(
+ "Invalid query flow",
+ IgniteQueryErrorCode.UNKNOWN
+ );
+ }
+
+ if (pctx == null) {
+ state = QueryState.PLANNING;
+
+ pctx = PlanningContext.builder()
+ .parentContext(ctx)
+ .query(sql)
+ .parameters(params)
+ .plannerTimeout(plannerTimeout)
+ .build();
+
+ try {
+ cancel.add(() -> pctx.unwrap(CancelFlag.class).requestCancel());
+ }
+ catch (QueryCancelledException e) {
+ throw new IgniteSQLException(e.getMessage(), IgniteQueryErrorCode.QUERY_CANCELED, e);
+ }
+ }
+
+ return pctx;
+ }
+ }
+
+ /** */
+ public Iterator<RowT> iterator() {
+ return root;
+ }
+
+ /** */
+ public long localQueryId() {
+ return locQryId;
+ }
+
+ /** */
+ public void localQueryId(long locQryId) {
+ this.locQryId = locQryId;
+ }
+
+ /** */
+ @Override public void onNodeLeft(UUID nodeId) {
+ List<RemoteFragmentKey> fragments = null;
+
+ synchronized (mux) {
+ fragments = waiting.stream().filter(f -> f.nodeId().equals(nodeId)).collect(Collectors.toList());
+ }
+
+ if (!F.isEmpty(fragments)) {
+ ClusterTopologyCheckedException ex = new ClusterTopologyCheckedException(
+ "Failed to start query, node left. nodeId=" + nodeId);
+
+ for (RemoteFragmentKey fragment : fragments)
+ onResponse(fragment, ex);
+ }
+ }
+
+ /** */
+ public void onResponse(UUID nodeId, long fragmentId, Throwable error) {
+ onResponse(new RemoteFragmentKey(nodeId, fragmentId), error);
+ }
+
+ /** */
+ private void onResponse(RemoteFragmentKey fragment, Throwable error) {
+ QueryState state;
+ synchronized (mux) {
+ waiting.remove(fragment);
+
+ state = this.state;
+ }
+
+ if (error != null)
+ onError(error);
+ else if (state == QueryState.CLOSING)
+ tryClose();
+ }
+
+ /** */
+ public void onError(Throwable error) {
+ root.onError(error);
+
+ tryClose();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onInboundExchangeStarted(UUID nodeId, long exchangeId) {
+ onResponse(nodeId, exchangeId, null);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onInboundExchangeFinished(UUID nodeId, long exchangeId) {
+ AtomicInteger cnt = remoteFragments.get(nodeId);
+
+ assert cnt != null : nodeId;
+
+ cnt.decrementAndGet();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onOutboundExchangeStarted(UUID nodeId, long exchangeId) {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onOutboundExchangeFinished(long exchangeId) {
+ // No-op.
+ }
+
+ /** */
+ @Override public String toString() {
+ return S.toString(RootQuery.class, this);
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RunningFragment.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RunningFragment.java
new file mode 100644
index 0000000..2627e022
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/RunningFragment.java
@@ -0,0 +1,79 @@
+/*
+ * 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.ignite.internal.processors.query.calcite;
+
+import java.util.Objects;
+
+import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.AbstractNode;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRel;
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+/** */
+public class RunningFragment<Row> {
+ /** Relation tree of the fragment is used to generate fragment human-readable description. */
+ private final IgniteRel rootRel;
+
+ /** */
+ private final AbstractNode<Row> root;
+
+ /** */
+ private final ExecutionContext<Row> ectx;
+
+ /** */
+ public RunningFragment(
+ IgniteRel rootRel,
+ AbstractNode<Row> root,
+ ExecutionContext<Row> ectx) {
+ this.rootRel = rootRel;
+ this.root = root;
+ this.ectx = ectx;
+ }
+
+ /** */
+ public ExecutionContext<Row> context() {
+ return ectx;
+ }
+
+ /** */
+ public AbstractNode<Row> root() {
+ return root;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ RunningFragment<Row> fragment = (RunningFragment<Row>)o;
+
+ return Objects.equals(ectx, fragment.ectx);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return Objects.hash(ectx);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(RunningFragment.class, this);
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/AbstractIndexScan.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/AbstractIndexScan.java
new file mode 100644
index 0000000..ca12e49
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/AbstractIndexScan.java
@@ -0,0 +1,165 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.cache.query.index.sorted.inline.IndexQueryContext;
+import org.apache.ignite.internal.util.lang.GridCursor;
+import org.apache.ignite.internal.util.lang.GridIteratorAdapter;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Abstract index scan.
+ */
+public abstract class AbstractIndexScan<Row, IdxRow> implements Iterable<Row>, AutoCloseable {
+ /** */
+ private final TreeIndex<IdxRow> idx;
+
+ /** Additional filters. */
+ private final Predicate<Row> filters;
+
+ /** Lower index scan bound. */
+ private final Supplier<Row> lowerBound;
+
+ /** Upper index scan bound. */
+ private final Supplier<Row> upperBound;
+
+ /** */
+ private final Function<Row, Row> rowTransformer;
+
+ /** */
+ protected final ExecutionContext<Row> ectx;
+
+ /** */
+ protected final RelDataType rowType;
+
+ /**
+ * @param ectx Execution context.
+ * @param idx Physical index.
+ * @param filters Additional filters.
+ * @param lowerBound Lower index scan bound.
+ * @param upperBound Upper index scan bound.
+ */
+ protected AbstractIndexScan(
+ ExecutionContext<Row> ectx,
+ RelDataType rowType,
+ TreeIndex<IdxRow> idx,
+ Predicate<Row> filters,
+ Supplier<Row> lowerBound,
+ Supplier<Row> upperBound,
+ Function<Row, Row> rowTransformer
+ ) {
+ this.ectx = ectx;
+ this.rowType = rowType;
+ this.idx = idx;
+ this.filters = filters;
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+ this.rowTransformer = rowTransformer;
+ }
+
+ /** {@inheritDoc} */
+ @Override public synchronized Iterator<Row> iterator() {
+ IdxRow lower = lowerBound == null ? null : row2indexRow(lowerBound.get());
+ IdxRow upper = upperBound == null ? null : row2indexRow(upperBound.get());
+
+ return new IteratorImpl(idx.find(lower, upper, indexQueryContext()));
+ }
+
+ /** */
+ protected abstract IdxRow row2indexRow(Row bound);
+
+ /** */
+ protected abstract Row indexRow2Row(IdxRow idxRow) throws IgniteCheckedException;
+
+ /** */
+ protected abstract IndexQueryContext indexQueryContext();
+
+ /** {@inheritDoc} */
+ @Override public void close() {
+ // No-op.
+ }
+
+ /** */
+ private class IteratorImpl extends GridIteratorAdapter<Row> {
+ /** */
+ private final GridCursor<IdxRow> cursor;
+
+ /** Next element. */
+ private Row next;
+
+ /** */
+ private IteratorImpl(@NotNull GridCursor<IdxRow> cursor) {
+ this.cursor = cursor;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean hasNextX() throws IgniteCheckedException {
+ advance();
+
+ return next != null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Row nextX() throws IgniteCheckedException {
+ advance();
+
+ if (next == null)
+ throw new NoSuchElementException();
+
+ Row res = next;
+
+ next = null;
+
+ return res;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void removeX() {
+ throw new UnsupportedOperationException("Remove is not supported.");
+ }
+
+ /** */
+ private void advance() throws IgniteCheckedException {
+ assert cursor != null;
+
+ if (next != null)
+ return;
+
+ while (next == null && cursor.next()) {
+ IdxRow idxRow = cursor.get();
+
+ Row r = indexRow2Row(idxRow);
+
+ if (filters != null && !filters.test(r))
+ continue;
+
+ if (rowTransformer != null)
+ r = rowTransformer.apply(r);
+
+ next = r;
+ }
+ }
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ArrayRowHandler.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ArrayRowHandler.java
new file mode 100644
index 0000000..be2eeb6
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ArrayRowHandler.java
@@ -0,0 +1,77 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.lang.reflect.Type;
+
+import org.apache.ignite.internal.util.typedef.F;
+
+/**
+ * Handler for rows that implemented as a simple objects array.
+ */
+public class ArrayRowHandler implements RowHandler<Object[]> {
+ /** */
+ public static final RowHandler<Object[]> INSTANCE = new ArrayRowHandler();
+
+ /** */
+ private ArrayRowHandler() {}
+
+ /** {@inheritDoc} */
+ @Override public Object get(int field, Object[] row) {
+ return row[field];
+ }
+
+ /** {@inheritDoc} */
+ @Override public void set(int field, Object[] row, Object val) {
+ row[field] = val;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object[] concat(Object[] left, Object[] right) {
+ return F.concat(left, right);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int columnCount(Object[] row) {
+ return row.length;
+ }
+
+ /** {@inheritDoc} */
+ @Override public RowFactory<Object[]> factory(Type... types) {
+ int rowLen = types.length;
+
+ return new RowFactory<Object[]>() {
+ /** {@inheritDoc} */
+ @Override public RowHandler<Object[]> handler() {
+ return ArrayRowHandler.this;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object[] create() {
+ return new Object[rowLen];
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object[] create(Object... fields) {
+ assert fields.length == rowLen;
+
+ return fields;
+ }
+ };
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ClosableIteratorsHolder.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ClosableIteratorsHolder.java
new file mode 100644
index 0000000..caae30f
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ClosableIteratorsHolder.java
@@ -0,0 +1,165 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.internal.processors.query.calcite.util.Commons;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class ClosableIteratorsHolder {
+ /** */
+ private final ReferenceQueue refQueue;
+
+ /** */
+ private final Map<Reference, Object> refMap;
+
+ /** */
+ private final IgniteLogger log;
+
+ /** */
+ private volatile boolean stopped;
+
+ /** */
+ private Thread cleanWorker;
+
+ /** */
+ public ClosableIteratorsHolder(IgniteLogger log) {
+ this.log = log;
+
+ refQueue = new ReferenceQueue<>();
+ refMap = new ConcurrentHashMap<>();
+ }
+
+ /**
+ * @param src Closeable iterator.
+ * @return Weak closable iterator wrapper.
+ */
+ public <T> Iterator<T> iterator(final Iterator<T> src) {
+ cleanUp(false);
+
+ return new DelegatingIterator<>(src);
+ }
+
+ /** */
+ public void init() {
+ cleanWorker = new Thread(() -> cleanUp(true), "ignite-calcite-iterators-cleanup");
+ cleanWorker.setDaemon(true);
+ cleanWorker.start();
+ }
+
+ /** */
+ public void tearDown() {
+ stopped = true;
+ refMap.clear();
+ U.interrupt(cleanWorker);
+ }
+
+ /** */
+ private void cleanUp(boolean blocking) {
+ for (Reference<?> ref = nextRef(blocking); !stopped && ref != null; ref = nextRef(blocking))
+ Commons.close(refMap.remove(ref), log);
+ }
+
+ /** */
+ private Reference nextRef(boolean blocking) {
+ try {
+ return !blocking ? refQueue.poll() : refQueue.remove();
+ }
+ catch (InterruptedException ignored) {
+ return null;
+ }
+ }
+
+ /** */
+ private AutoCloseable closeable(Object referent, Object resource) {
+ if (!(resource instanceof AutoCloseable))
+ return null;
+
+ return new CloseableReference(referent, resource);
+ }
+
+ /** */
+ private final class DelegatingIterator<T> implements Iterator<T>, AutoCloseable {
+ /** */
+ private final Iterator<T> delegate;
+
+ /** */
+ private final AutoCloseable closeable;
+
+ /** */
+ private DelegatingIterator(Iterator<T> delegate) {
+ closeable = closeable(this, this.delegate = delegate);
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean hasNext() {
+ return delegate.hasNext();
+ }
+
+ /** {@inheritDoc} */
+ @Override public T next() {
+ return delegate.next();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void remove() {
+ delegate.remove();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void forEachRemaining(Consumer<? super T> action) {
+ delegate.forEachRemaining(action);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close() throws Exception {
+ Commons.close(closeable);
+ }
+ }
+
+ /** */
+ private final class CloseableReference extends WeakReference implements AutoCloseable {
+ /** */
+ private CloseableReference(Object referent, Object resource) {
+ super(referent, refQueue);
+
+ refMap.put(this, resource);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close() throws Exception {
+ try {
+ Commons.close(refMap.remove(this));
+ }
+ finally {
+ clear();
+ }
+ }
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExchangeService.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExchangeService.java
new file mode 100644
index 0000000..5c618d2
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExchangeService.java
@@ -0,0 +1,93 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.processors.query.calcite.util.Service;
+
+/**
+ *
+ */
+public interface ExchangeService extends Service {
+ /**
+ * Sends a batch of data to remote node.
+ * @param nodeId Target node ID.
+ * @param qryId Query ID.
+ * @param fragmentId Target fragment ID.
+ * @param exchangeId Exchange ID.
+ * @param batchId Batch ID.
+ * @param last Last batch flag.
+ * @param rows Data rows.
+ */
+ <Row> void sendBatch(UUID nodeId, UUID qryId, long fragmentId, long exchangeId, int batchId, boolean last,
+ List<Row> rows) throws IgniteCheckedException;
+
+ /**
+ * Acknowledges a batch with given ID is processed.
+ * @param nodeId Node ID to notify.
+ * @param qryId Query ID.
+ * @param fragmentId Target fragment ID.
+ * @param exchangeId Exchange ID.
+ * @param batchId Batch ID.
+ */
+ void acknowledge(UUID nodeId, UUID qryId, long fragmentId, long exchangeId, int batchId) throws IgniteCheckedException;
+
+ /**
+ * Sends cancel request.
+ * @param nodeId Target node ID.
+ * @param qryId Query ID.
+ * @param fragmentId Target fragment ID.
+ * @param exchangeId Exchange ID.
+ */
+ void closeInbox(UUID nodeId, UUID qryId, long fragmentId, long exchangeId) throws IgniteCheckedException;
+
+ /**
+ * Sends cancel request.
+ * @param nodeId Target node ID.
+ * @param qryId Query ID.
+ */
+ void closeQuery(UUID nodeId, UUID qryId) throws IgniteCheckedException;
+
+ /**
+ * @param nodeId Target node ID.
+ * @param qryId Query ID.
+ * @param fragmentId Source fragment ID.
+ * @param err Exception to send.
+ * @throws IgniteCheckedException On error marshaling or send ErrorMessage.
+ */
+ void sendError(UUID nodeId, UUID qryId, long fragmentId, Throwable err) throws IgniteCheckedException;
+
+ /**
+ * @param nodeId Node ID.
+ * @return {@code true} if node is alive, {@code false} otherwise.
+ */
+ boolean alive(UUID nodeId);
+
+ /**
+ * Callback after the last batch of the query fragment is sent.
+ */
+ void onOutboundExchangeFinished(UUID qryId, long exchangeId);
+
+ /**
+ * Callback after the last batch of the query fragment from the node is processed.
+ */
+ void onInboundExchangeFinished(UUID nodeId, UUID qryId, long exchangeId);
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExchangeServiceImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExchangeServiceImpl.java
new file mode 100644
index 0000000..2a2a246
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExchangeServiceImpl.java
@@ -0,0 +1,316 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.query.RunningQuery;
+import org.apache.ignite.internal.processors.query.calcite.CalciteQueryProcessor;
+import org.apache.ignite.internal.processors.query.calcite.Query;
+import org.apache.ignite.internal.processors.query.calcite.QueryRegistry;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Inbox;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Outbox;
+import org.apache.ignite.internal.processors.query.calcite.message.ErrorMessage;
+import org.apache.ignite.internal.processors.query.calcite.message.InboxCloseMessage;
+import org.apache.ignite.internal.processors.query.calcite.message.MessageService;
+import org.apache.ignite.internal.processors.query.calcite.message.MessageType;
+import org.apache.ignite.internal.processors.query.calcite.message.QueryBatchAcknowledgeMessage;
+import org.apache.ignite.internal.processors.query.calcite.message.QueryBatchMessage;
+import org.apache.ignite.internal.processors.query.calcite.message.QueryCloseMessage;
+import org.apache.ignite.internal.processors.query.calcite.metadata.FragmentDescription;
+import org.apache.ignite.internal.processors.query.calcite.prepare.BaseQueryContext;
+import org.apache.ignite.internal.processors.query.calcite.util.AbstractService;
+import org.apache.ignite.internal.processors.query.calcite.util.Commons;
+import org.apache.ignite.internal.util.typedef.F;
+
+/**
+ *
+ */
+public class ExchangeServiceImpl extends AbstractService implements ExchangeService {
+ /** */
+ private final UUID locaNodeId;
+
+ /** */
+ private QueryTaskExecutor taskExecutor;
+
+ /** */
+ private MailboxRegistry mailboxRegistry;
+
+ /** */
+ private MessageService msgSvc;
+
+ /** */
+ private QueryRegistry qryRegistry;
+
+ /**
+ * @param ctx Kernal context.
+ */
+ public ExchangeServiceImpl(GridKernalContext ctx) {
+ super(ctx);
+
+ locaNodeId = ctx.localNodeId();
+ }
+
+ /**
+ * @param taskExecutor Task executor.
+ */
+ public void taskExecutor(QueryTaskExecutor taskExecutor) {
+ this.taskExecutor = taskExecutor;
+ }
+
+ /**
+ * @return Task executor.
+ */
+ public QueryTaskExecutor taskExecutor() {
+ return taskExecutor;
+ }
+
+ /**
+ * @param mailboxRegistry Mailbox registry.
+ */
+ public void mailboxRegistry(MailboxRegistry mailboxRegistry) {
+ this.mailboxRegistry = mailboxRegistry;
+ }
+
+ /**
+ * @return Mailbox registry.
+ */
+ public MailboxRegistry mailboxRegistry() {
+ return mailboxRegistry;
+ }
+
+ /**
+ * @param msgSvc Message service.
+ */
+ public void messageService(MessageService msgSvc) {
+ this.msgSvc = msgSvc;
+ }
+
+ /**
+ * @return Message service.
+ */
+ public MessageService messageService() {
+ return msgSvc;
+ }
+
+ /** */
+ public void queryRegistry(QueryRegistry qryRegistry) {
+ this.qryRegistry = qryRegistry;
+ }
+
+ /** {@inheritDoc} */
+ @Override public <Row> void sendBatch(UUID nodeId, UUID qryId, long fragmentId, long exchangeId, int batchId,
+ boolean last, List<Row> rows) throws IgniteCheckedException {
+ messageService().send(nodeId, new QueryBatchMessage(qryId, fragmentId, exchangeId, batchId, last, Commons.cast(rows)));
+
+ if (batchId == 0) {
+ Query<?> qry = (Query<?>)qryRegistry.query(qryId);
+
+ if (qry != null)
+ qry.onOutboundExchangeStarted(nodeId, exchangeId);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public void acknowledge(UUID nodeId, UUID qryId, long fragmentId, long exchangeId, int batchId)
+ throws IgniteCheckedException {
+ messageService().send(nodeId, new QueryBatchAcknowledgeMessage(qryId, fragmentId, exchangeId, batchId));
+ }
+
+ /** {@inheritDoc} */
+ @Override public void closeQuery(UUID nodeId, UUID qryId) throws IgniteCheckedException {
+ messageService().send(nodeId, new QueryCloseMessage(qryId));
+ }
+
+ /** {@inheritDoc} */
+ @Override public void closeInbox(UUID nodeId, UUID qryId, long fragmentId, long exchangeId) throws IgniteCheckedException {
+ messageService().send(nodeId, new InboxCloseMessage(qryId, fragmentId, exchangeId));
+ }
+
+ /** {@inheritDoc} */
+ @Override public void sendError(UUID nodeId, UUID qryId, long fragmentId, Throwable err) throws IgniteCheckedException {
+ messageService().send(nodeId, new ErrorMessage(qryId, fragmentId, err));
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onStart(GridKernalContext ctx) {
+ CalciteQueryProcessor proc =
+ Objects.requireNonNull(Commons.lookupComponent(ctx, CalciteQueryProcessor.class));
+
+ taskExecutor(proc.taskExecutor());
+ mailboxRegistry(proc.mailboxRegistry());
+ messageService(proc.messageService());
+ queryRegistry(proc.queryRegistry());
+
+ init();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void init() {
+ messageService().register((n, m) -> onMessage(n, (InboxCloseMessage)m), MessageType.QUERY_INBOX_CANCEL_MESSAGE);
+ messageService().register((n, m) -> onMessage(n, (QueryBatchAcknowledgeMessage)m), MessageType.QUERY_ACKNOWLEDGE_MESSAGE);
+ messageService().register((n, m) -> onMessage(n, (QueryBatchMessage)m), MessageType.QUERY_BATCH_MESSAGE);
+ messageService().register((n, m) -> onMessage(n, (QueryCloseMessage)m), MessageType.QUERY_CLOSE_MESSAGE);
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean alive(UUID nodeId) {
+ return messageService().alive(nodeId);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onOutboundExchangeFinished(UUID qryId, long exchangeId) {
+ Query<?> qry = (Query<?>)qryRegistry.query(qryId);
+
+ if (qry != null)
+ qry.onOutboundExchangeFinished(exchangeId);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onInboundExchangeFinished(UUID nodeId, UUID qryId, long exchangeId) {
+ Query<?> qry = (Query<?>)qryRegistry.query(qryId);
+
+ if (qry != null)
+ qry.onInboundExchangeFinished(nodeId, exchangeId);
+ }
+
+ /** */
+ protected void onMessage(UUID nodeId, InboxCloseMessage msg) {
+ Collection<Inbox<?>> inboxes = mailboxRegistry().inboxes(msg.queryId(), msg.fragmentId(), msg.exchangeId());
+
+ if (!F.isEmpty(inboxes)) {
+ for (Inbox<?> inbox : inboxes)
+ inbox.context().execute(inbox::close, inbox::onError);
+ }
+ else if (log.isDebugEnabled()) {
+ log.debug("Stale inbox cancel message received: [" +
+ "nodeId=" + nodeId +
+ ", queryId=" + msg.queryId() +
+ ", fragmentId=" + msg.fragmentId() +
+ ", exchangeId=" + msg.exchangeId() + "]");
+ }
+ }
+
+ /** */
+ protected void onMessage(UUID nodeId, QueryCloseMessage msg) {
+ RunningQuery qry = qryRegistry.query(msg.queryId());
+
+ if (qry != null)
+ qry.cancel();
+ else {
+ if (log.isDebugEnabled()) {
+ log.debug("Stale query close message received: [" +
+ "nodeId=" + nodeId +
+ ", queryId=" + msg.queryId() + "]");
+ }
+ }
+ }
+
+ /** */
+ protected void onMessage(UUID nodeId, QueryBatchAcknowledgeMessage msg) {
+ Outbox<?> outbox = mailboxRegistry().outbox(msg.queryId(), msg.exchangeId());
+
+ if (outbox != null) {
+ try {
+ outbox.onAcknowledge(nodeId, msg.batchId());
+ }
+ catch (Throwable e) {
+ outbox.onError(e);
+
+ throw new IgniteException("Unexpected exception", e);
+ }
+ }
+ else if (log.isDebugEnabled()) {
+ log.debug("Stale acknowledge message received: [" +
+ "nodeId=" + nodeId + ", " +
+ "queryId=" + msg.queryId() + ", " +
+ "fragmentId=" + msg.fragmentId() + ", " +
+ "exchangeId=" + msg.exchangeId() + ", " +
+ "batchId=" + msg.batchId() + "]");
+ }
+ }
+
+ /** */
+ protected void onMessage(UUID nodeId, QueryBatchMessage msg) {
+ Inbox<?> inbox = mailboxRegistry().inbox(msg.queryId(), msg.exchangeId());
+
+ if (inbox == null && msg.batchId() == 0) {
+ // first message sent before a fragment is built
+ // note that an inbox source fragment id is also used as an exchange id
+ Inbox<?> newInbox = new Inbox<>(baseInboxContext(nodeId, msg.queryId(), msg.fragmentId()),
+ this, mailboxRegistry(), msg.exchangeId(), msg.exchangeId());
+
+ inbox = mailboxRegistry().register(newInbox);
+ }
+
+ if (inbox != null) {
+ try {
+ if (msg.batchId() == 0) {
+ Query<?> qry = (Query<?>)qryRegistry.query(msg.queryId());
+
+ if (qry != null)
+ qry.onInboundExchangeStarted(nodeId, msg.exchangeId());
+ }
+
+ inbox.onBatchReceived(nodeId, msg.batchId(), msg.last(), Commons.cast(msg.rows()));
+ }
+ catch (Throwable e) {
+ inbox.onError(e);
+
+ throw new IgniteException("Unexpected exception", e);
+ }
+ }
+ else if (log.isDebugEnabled()) {
+ log.debug("Stale batch message received: [" +
+ "nodeId=" + nodeId + ", " +
+ "queryId=" + msg.queryId() + ", " +
+ "fragmentId=" + msg.fragmentId() + ", " +
+ "exchangeId=" + msg.exchangeId() + ", " +
+ "batchId=" + msg.batchId() + "]");
+ }
+ }
+
+ /**
+ * @return Minimal execution context to meet Inbox needs.
+ */
+ private ExecutionContext<?> baseInboxContext(UUID nodeId, UUID qryId, long fragmentId) {
+ return new ExecutionContext<>(
+ BaseQueryContext.builder()
+ .logger(log)
+ .build(),
+ taskExecutor(),
+ qryId,
+ locaNodeId,
+ nodeId,
+ null,
+ new FragmentDescription(
+ fragmentId,
+ null,
+ null,
+ null),
+ null,
+ ImmutableMap.of());
+ }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionCancelledException.java
similarity index 53%
copy from modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java
copy to modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionCancelledException.java
index 38f3f67a..fb4a8d8 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionCancelledException.java
@@ -15,30 +15,10 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.processors.query.stat;
+package org.apache.ignite.internal.processors.query.calcite.exec;
-import org.jetbrains.annotations.Nullable;
+import org.apache.ignite.IgniteCheckedException;
-/**
- * Types of statistics width.
- */
-public enum StatisticsType {
- /** Statistics by some particular partition. */
- PARTITION,
-
- /** Statistics by some data node. */
- LOCAL;
-
- /** Enumerated values. */
- private static final StatisticsType[] VALUES = values();
-
- /**
- * Efficiently gets enumerated value from its ordinal.
- *
- * @param ord Ordinal value.
- * @return Enumerated value or {@code null} if ordinal out of range.
- */
- @Nullable public static StatisticsType fromOrdinal(int ord) {
- return ord >= 0 && ord < VALUES.length ? VALUES[ord] : null;
- }
+/** */
+public class ExecutionCancelledException extends IgniteCheckedException {
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionContext.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionContext.java
new file mode 100644
index 0000000..fd0cf9e
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionContext.java
@@ -0,0 +1,327 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+import org.apache.calcite.DataContext;
+import org.apache.calcite.linq4j.QueryProvider;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot;
+import org.apache.ignite.internal.processors.query.calcite.exec.exp.ExpressionFactory;
+import org.apache.ignite.internal.processors.query.calcite.exec.exp.ExpressionFactoryImpl;
+import org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGroup;
+import org.apache.ignite.internal.processors.query.calcite.metadata.FragmentDescription;
+import org.apache.ignite.internal.processors.query.calcite.prepare.AbstractQueryContext;
+import org.apache.ignite.internal.processors.query.calcite.prepare.BaseDataContext;
+import org.apache.ignite.internal.processors.query.calcite.prepare.BaseQueryContext;
+import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
+import org.apache.ignite.internal.processors.query.calcite.util.Commons;
+import org.apache.ignite.internal.processors.query.calcite.util.TypeUtils;
+import org.jetbrains.annotations.NotNull;
+
+import static org.apache.ignite.internal.processors.query.calcite.util.Commons.checkRange;
+
+/**
+ * Runtime context allowing access to the tables in a database.
+ */
+public class ExecutionContext<Row> extends AbstractQueryContext implements DataContext {
+ /** Placeholder for values, which expressions is not specified. */
+ private static final Object UNSPECIFIED_VALUE = new Object();
+
+ /** */
+ private final UUID qryId;
+
+ /** */
+ private final UUID locNodeId;
+
+ /** */
+ private final UUID originatingNodeId;
+
+ /** */
+ private final AffinityTopologyVersion topVer;
+
+ /** */
+ private final FragmentDescription fragmentDesc;
+
+ /** */
+ private final Map<String, Object> params;
+
+ /** */
+ private final QueryTaskExecutor executor;
+
+ /** */
+ private final RowHandler<Row> handler;
+
+ /** */
+ private final ExpressionFactory<Row> expressionFactory;
+
+ /** */
+ private final AtomicBoolean cancelFlag = new AtomicBoolean();
+
+ /** */
+ private final BaseDataContext baseDataContext;
+
+ /** */
+ private Object[] correlations = new Object[16];
+
+ /**
+ * @param qctx Parent base query context.
+ * @param qryId Query ID.
+ * @param fragmentDesc Partitions information.
+ * @param params Parameters.
+ */
+ @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType")
+ public ExecutionContext(
+ BaseQueryContext qctx,
+ QueryTaskExecutor executor,
+ UUID qryId,
+ UUID locNodeId,
+ UUID originatingNodeId,
+ AffinityTopologyVersion topVer,
+ FragmentDescription fragmentDesc,
+ RowHandler<Row> handler,
+ Map<String, Object> params
+ ) {
+ super(qctx);
+
+ this.executor = executor;
+ this.qryId = qryId;
+ this.locNodeId = locNodeId;
+ this.originatingNodeId = originatingNodeId;
+ this.topVer = topVer;
+ this.fragmentDesc = fragmentDesc;
+ this.handler = handler;
+ this.params = params;
+
+ baseDataContext = new BaseDataContext(qctx.typeFactory());
+
+ expressionFactory = new ExpressionFactoryImpl<>(
+ this,
+ qctx.typeFactory(),
+ qctx.config().getParserConfig().conformance(),
+ qctx.rexBuilder()
+ );
+ }
+
+ /**
+ * @return Query ID.
+ */
+ public UUID queryId() {
+ return qryId;
+ }
+
+ /**
+ * @return Fragment ID.
+ */
+ public long fragmentId() {
+ return fragmentDesc.fragmentId();
+ }
+
+ /**
+ * @return Target mapping.
+ */
+ public ColocationGroup target() {
+ return fragmentDesc.target();
+ }
+
+ /** */
+ public List<UUID> remotes(long exchangeId) {
+ return fragmentDesc.remotes().get(exchangeId);
+ }
+
+ /** */
+ public ColocationGroup group(long sourceId) {
+ return fragmentDesc.mapping().findGroup(sourceId);
+ }
+
+ /**
+ * @return Keep binary flag.
+ */
+ public boolean keepBinary() {
+ return true; // TODO
+ }
+
+ /**
+ * @return MVCC snapshot.
+ */
+ public MvccSnapshot mvccSnapshot() {
+ return null; // TODO
+ }
+
+ /**
+ * @return Handler to access row fields.
+ */
+ public RowHandler<Row> rowHandler() {
+ return handler;
+ }
+
+ /**
+ * @return Expression factory.
+ */
+ public ExpressionFactory<Row> expressionFactory() {
+ return expressionFactory;
+ }
+
+ /**
+ * @return Local node ID.
+ */
+ public UUID localNodeId() {
+ return locNodeId;
+ }
+
+ /**
+ * @return Originating node ID (the node, who started the execution).
+ */
+ public UUID originatingNodeId() {
+ return originatingNodeId;
+ }
+
+ /**
+ * @return Topology version.
+ */
+ public AffinityTopologyVersion topologyVersion() {
+ return topVer;
+ }
+
+ /** */
+ public IgniteLogger logger() {
+ return unwrap(BaseQueryContext.class).logger();
+ }
+
+ /** {@inheritDoc} */
+ @Override public SchemaPlus getRootSchema() {
+ return baseDataContext.getRootSchema();
+ }
+
+ /** {@inheritDoc} */
+ @Override public IgniteTypeFactory getTypeFactory() {
+ return baseDataContext.getTypeFactory();
+ }
+
+ /** {@inheritDoc} */
+ @Override public QueryProvider getQueryProvider() {
+ return baseDataContext.getQueryProvider();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Object get(String name) {
+ if (Variable.CANCEL_FLAG.camelName.equals(name))
+ return cancelFlag;
+ if (name.startsWith("?"))
+ return TypeUtils.toInternal(this, params.get(name));
+
+ return baseDataContext.get(name);
+ }
+
+ /**
+ * Gets correlated value.
+ *
+ * @param id Correlation ID.
+ * @return Correlated value.
+ */
+ public @NotNull Object getCorrelated(int id) {
+ checkRange(correlations, id);
+
+ return correlations[id];
+ }
+
+ /**
+ * Sets correlated value.
+ *
+ * @param id Correlation ID.
+ * @param value Correlated value.
+ */
+ public void setCorrelated(@NotNull Object value, int id) {
+ correlations = Commons.ensureCapacity(correlations, id + 1);
+
+ correlations[id] = value;
+ }
+
+ /**
+ * Executes a query task.
+ *
+ * @param task Query task.
+ */
+ public void execute(RunnableX task, Consumer<Throwable> onError) {
+ if (isCancelled())
+ return;
+
+ executor.execute(qryId, fragmentId(), () -> {
+ try {
+ if (!isCancelled())
+ task.run();
+ }
+ catch (Throwable e) {
+ onError.accept(e);
+
+ throw new IgniteException("Unexpected exception", e);
+ }
+ });
+ }
+
+ /** */
+ @FunctionalInterface
+ public interface RunnableX {
+ /** */
+ void run() throws Exception;
+ }
+
+ /**
+ * Sets cancel flag, returns {@code true} if flag was changed by this call.
+ *
+ * @return {@code True} if flag was changed by this call.
+ */
+ public boolean cancel() {
+ return !cancelFlag.get() && cancelFlag.compareAndSet(false, true);
+ }
+
+ /** */
+ public boolean isCancelled() {
+ return cancelFlag.get();
+ }
+
+ /** */
+ public Object unspecifiedValue() {
+ return UNSPECIFIED_VALUE;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ ExecutionContext<?> context = (ExecutionContext<?>)o;
+
+ return qryId.equals(context.qryId) && fragmentDesc.fragmentId() == context.fragmentDesc.fragmentId();
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return Objects.hash(qryId, fragmentDesc.fragmentId());
+ }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionService.java
similarity index 53%
copy from modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java
copy to modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionService.java
index 38f3f67a..a3fbf2c 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionService.java
@@ -15,30 +15,19 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.processors.query.stat;
+package org.apache.ignite.internal.processors.query.calcite.exec;
-import org.jetbrains.annotations.Nullable;
+import java.util.List;
+
+import org.apache.ignite.cache.query.FieldsQueryCursor;
+import org.apache.ignite.internal.processors.query.calcite.RootQuery;
+import org.apache.ignite.internal.processors.query.calcite.prepare.QueryPlan;
+import org.apache.ignite.internal.processors.query.calcite.util.Service;
/**
- * Types of statistics width.
+ *
*/
-public enum StatisticsType {
- /** Statistics by some particular partition. */
- PARTITION,
-
- /** Statistics by some data node. */
- LOCAL;
-
- /** Enumerated values. */
- private static final StatisticsType[] VALUES = values();
-
- /**
- * Efficiently gets enumerated value from its ordinal.
- *
- * @param ord Ordinal value.
- * @return Enumerated value or {@code null} if ordinal out of range.
- */
- @Nullable public static StatisticsType fromOrdinal(int ord) {
- return ord >= 0 && ord < VALUES.length ? VALUES[ord] : null;
- }
+public interface ExecutionService<Row> extends Service {
+ /** */
+ FieldsQueryCursor<List<?>> executePlan(RootQuery<Row> qry, QueryPlan plan);
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java
new file mode 100644
index 0000000..60c5ee1
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ExecutionServiceImpl.java
@@ -0,0 +1,757 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.apache.calcite.plan.Context;
+import org.apache.calcite.plan.Contexts;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.sql.SqlInsert;
+import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.tools.Frameworks;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.cache.query.FieldsQueryCursor;
+import org.apache.ignite.events.EventType;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.managers.eventstorage.DiscoveryEventListener;
+import org.apache.ignite.internal.managers.eventstorage.GridEventStorageManager;
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cache.GridCachePartitionExchangeManager;
+import org.apache.ignite.internal.processors.cache.QueryCursorImpl;
+import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
+import org.apache.ignite.internal.processors.failure.FailureProcessor;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.processors.query.QueryState;
+import org.apache.ignite.internal.processors.query.RunningQuery;
+import org.apache.ignite.internal.processors.query.calcite.CalciteQueryProcessor;
+import org.apache.ignite.internal.processors.query.calcite.Query;
+import org.apache.ignite.internal.processors.query.calcite.QueryRegistry;
+import org.apache.ignite.internal.processors.query.calcite.RootQuery;
+import org.apache.ignite.internal.processors.query.calcite.RunningFragment;
+import org.apache.ignite.internal.processors.query.calcite.exec.ddl.DdlCommandHandler;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Inbox;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Node;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Outbox;
+import org.apache.ignite.internal.processors.query.calcite.message.ErrorMessage;
+import org.apache.ignite.internal.processors.query.calcite.message.MessageService;
+import org.apache.ignite.internal.processors.query.calcite.message.MessageType;
+import org.apache.ignite.internal.processors.query.calcite.message.QueryStartRequest;
+import org.apache.ignite.internal.processors.query.calcite.message.QueryStartResponse;
+import org.apache.ignite.internal.processors.query.calcite.metadata.AffinityService;
+import org.apache.ignite.internal.processors.query.calcite.metadata.FragmentDescription;
+import org.apache.ignite.internal.processors.query.calcite.metadata.FragmentMapping;
+import org.apache.ignite.internal.processors.query.calcite.metadata.MappingService;
+import org.apache.ignite.internal.processors.query.calcite.metadata.RemoteException;
+import org.apache.ignite.internal.processors.query.calcite.prepare.BaseQueryContext;
+import org.apache.ignite.internal.processors.query.calcite.prepare.CacheKey;
+import org.apache.ignite.internal.processors.query.calcite.prepare.DdlPlan;
+import org.apache.ignite.internal.processors.query.calcite.prepare.ExplainPlan;
+import org.apache.ignite.internal.processors.query.calcite.prepare.FieldsMetadata;
+import org.apache.ignite.internal.processors.query.calcite.prepare.FieldsMetadataImpl;
+import org.apache.ignite.internal.processors.query.calcite.prepare.Fragment;
+import org.apache.ignite.internal.processors.query.calcite.prepare.FragmentPlan;
+import org.apache.ignite.internal.processors.query.calcite.prepare.MappingQueryContext;
+import org.apache.ignite.internal.processors.query.calcite.prepare.MultiStepPlan;
+import org.apache.ignite.internal.processors.query.calcite.prepare.PlanningContext;
+import org.apache.ignite.internal.processors.query.calcite.prepare.PrepareServiceImpl;
+import org.apache.ignite.internal.processors.query.calcite.prepare.QueryPlan;
+import org.apache.ignite.internal.processors.query.calcite.prepare.QueryPlanCache;
+import org.apache.ignite.internal.processors.query.calcite.prepare.ddl.CreateTableCommand;
+import org.apache.ignite.internal.processors.query.calcite.schema.SchemaHolder;
+import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
+import org.apache.ignite.internal.processors.query.calcite.util.AbstractService;
+import org.apache.ignite.internal.processors.query.calcite.util.Commons;
+import org.apache.ignite.internal.processors.query.calcite.util.ListFieldsQueryCursor;
+import org.apache.ignite.internal.processors.query.calcite.util.TypeUtils;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.X;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.jetbrains.annotations.Nullable;
+
+import static java.util.Collections.singletonList;
+import static org.apache.ignite.internal.processors.query.calcite.CalciteQueryProcessor.FRAMEWORK_CONFIG;
+import static org.apache.ignite.internal.processors.query.calcite.externalize.RelJsonReader.fromJson;
+
+/**
+ *
+ */
+@SuppressWarnings("TypeMayBeWeakened")
+public class ExecutionServiceImpl<Row> extends AbstractService implements ExecutionService<Row> {
+ /** */
+ private final DiscoveryEventListener discoLsnr;
+
+ /** */
+ private UUID locNodeId;
+
+ /** */
+ private GridEventStorageManager evtMgr;
+
+ /** */
+ private GridCachePartitionExchangeManager<?, ?> exchangeMgr;
+
+ /** */
+ private QueryPlanCache qryPlanCache;
+
+ /** */
+ private SchemaHolder schemaHolder;
+
+ /** */
+ private QueryTaskExecutor taskExecutor;
+
+ /** */
+ private FailureProcessor failureProcessor;
+
+ /** */
+ private AffinityService partSvc;
+
+ /** */
+ private MailboxRegistry mailboxRegistry;
+
+ /** */
+ private MappingService mappingSvc;
+
+ /** */
+ private MessageService msgSvc;
+
+ /** */
+ private ExchangeService exchangeSvc;
+
+ /** */
+ private PrepareServiceImpl prepareSvc;
+
+ /** */
+ private ClosableIteratorsHolder iteratorsHolder;
+
+ /** */
+ private QueryRegistry qryReg;
+
+ /** */
+ private final RowHandler<Row> handler;
+
+ /** */
+ private final DdlCommandHandler ddlCmdHnd;
+
+ /**
+ * @param ctx Kernal.
+ */
+ public ExecutionServiceImpl(GridKernalContext ctx, RowHandler<Row> handler) {
+ super(ctx);
+ this.handler = handler;
+
+ discoLsnr = (e, c) -> onNodeLeft(e.eventNode().id());
+
+ ddlCmdHnd = new DdlCommandHandler(
+ ctx::query, ctx.cache(), ctx.security(), () -> schemaHolder().schema(null)
+ );
+ }
+
+ /**
+ * @param locNodeId Local node ID.
+ */
+ public void localNodeId(UUID locNodeId) {
+ this.locNodeId = locNodeId;
+ }
+
+ /**
+ * @return Local node ID.
+ */
+ public UUID localNodeId() {
+ return locNodeId;
+ }
+
+ /**
+ * @param qryPlanCache Query cache.
+ */
+ public void queryPlanCache(QueryPlanCache qryPlanCache) {
+ this.qryPlanCache = qryPlanCache;
+ }
+
+ /**
+ * @return Query cache.
+ */
+ public QueryPlanCache queryPlanCache() {
+ return qryPlanCache;
+ }
+
+ /**
+ * @param schemaHolder Schema holder.
+ */
+ public void schemaHolder(SchemaHolder schemaHolder) {
+ this.schemaHolder = schemaHolder;
+ }
+
+ /**
+ * @return Schema holder.
+ */
+ public SchemaHolder schemaHolder() {
+ return schemaHolder;
+ }
+
+ /**
+ * @param taskExecutor Task executor.
+ */
+ public void taskExecutor(QueryTaskExecutor taskExecutor) {
+ this.taskExecutor = taskExecutor;
+ }
+
+ /**
+ * @return Task executor.
+ */
+ public QueryTaskExecutor taskExecutor() {
+ return taskExecutor;
+ }
+
+ /**
+ * @param failureProcessor Failure processor.
+ */
+ public void failureProcessor(FailureProcessor failureProcessor) {
+ this.failureProcessor = failureProcessor;
+ }
+
+ /**
+ * @return Failure processor.
+ */
+ public FailureProcessor failureProcessor() {
+ return failureProcessor;
+ }
+
+ /**
+ * @param partSvc Partition service.
+ */
+ public void partitionService(AffinityService partSvc) {
+ this.partSvc = partSvc;
+ }
+
+ /**
+ * @return Partition service.
+ */
+ public AffinityService partitionService() {
+ return partSvc;
+ }
+
+ /**
+ * @param mailboxRegistry Mailbox registry.
+ */
+ public void mailboxRegistry(MailboxRegistry mailboxRegistry) {
+ this.mailboxRegistry = mailboxRegistry;
+ }
+
+ /**
+ * @return Mailbox registry.
+ */
+ public MailboxRegistry mailboxRegistry() {
+ return mailboxRegistry;
+ }
+
+ /**
+ * @param mappingSvc Mapping service.
+ */
+ public void mappingService(MappingService mappingSvc) {
+ this.mappingSvc = mappingSvc;
+ }
+
+ /**
+ * @return Mapping service.
+ */
+ public MappingService mappingService() {
+ return mappingSvc;
+ }
+
+ /**
+ * @param msgSvc Message service.
+ */
+ public void messageService(MessageService msgSvc) {
+ this.msgSvc = msgSvc;
+ }
+
+ /**
+ * @return Message service.
+ */
+ public MessageService messageService() {
+ return msgSvc;
+ }
+
+ /**
+ * @param exchangeSvc Exchange service.
+ */
+ public void exchangeService(ExchangeService exchangeSvc) {
+ this.exchangeSvc = exchangeSvc;
+ }
+
+ /**
+ * @param prepareSvc Prepare service.
+ */
+ public void prepareService(PrepareServiceImpl prepareSvc) {
+ this.prepareSvc = prepareSvc;
+ }
+
+ /**
+ * @return Exchange service.
+ */
+ public ExchangeService exchangeService() {
+ return exchangeSvc;
+ }
+
+ /**
+ * @param evtMgr Event manager.
+ */
+ public void eventManager(GridEventStorageManager evtMgr) {
+ this.evtMgr = evtMgr;
+ }
+
+ /**
+ * @return Event manager.
+ */
+ public GridEventStorageManager eventManager() {
+ return evtMgr;
+ }
+
+ /**
+ * @param exchangeMgr Exchange manager.
+ */
+ public void exchangeManager(GridCachePartitionExchangeManager<?, ?> exchangeMgr) {
+ this.exchangeMgr = exchangeMgr;
+ }
+
+ /**
+ * @return Exchange manager.
+ */
+ public GridCachePartitionExchangeManager<?, ?> exchangeManager() {
+ return exchangeMgr;
+ }
+
+ /**
+ * @param iteratorsHolder Iterators holder.
+ */
+ public void iteratorsHolder(ClosableIteratorsHolder iteratorsHolder) {
+ this.iteratorsHolder = iteratorsHolder;
+ }
+
+ /**
+ * @return Iterators holder.
+ */
+ public ClosableIteratorsHolder iteratorsHolder() {
+ return iteratorsHolder;
+ }
+
+ /** */
+ public void queryRegistry(QueryRegistry qryReg) {
+ this.qryReg = qryReg;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onStart(GridKernalContext ctx) {
+ localNodeId(ctx.localNodeId());
+ exchangeManager(ctx.cache().context().exchange());
+ eventManager(ctx.event());
+ iteratorsHolder(new ClosableIteratorsHolder(log));
+
+ CalciteQueryProcessor proc = Objects.requireNonNull(
+ Commons.lookupComponent(ctx, CalciteQueryProcessor.class));
+
+ queryPlanCache(proc.queryPlanCache());
+ schemaHolder(proc.schemaHolder());
+ taskExecutor(proc.taskExecutor());
+ failureProcessor(proc.failureProcessor());
+ partitionService(proc.affinityService());
+ mailboxRegistry(proc.mailboxRegistry());
+ mappingService(proc.mappingService());
+ messageService(proc.messageService());
+ exchangeService(proc.exchangeService());
+ queryRegistry(proc.queryRegistry());
+ prepareService(proc.prepareService());
+
+ init();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void init() {
+ messageService().register((n, m) -> onMessage(n, (QueryStartRequest)m), MessageType.QUERY_START_REQUEST);
+ messageService().register((n, m) -> onMessage(n, (QueryStartResponse)m), MessageType.QUERY_START_RESPONSE);
+ messageService().register((n, m) -> onMessage(n, (ErrorMessage)m), MessageType.QUERY_ERROR_MESSAGE);
+
+ eventManager().addDiscoveryEventListener(discoLsnr, EventType.EVT_NODE_FAILED, EventType.EVT_NODE_LEFT);
+
+ iteratorsHolder().init();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void tearDown() {
+ eventManager().removeDiscoveryEventListener(discoLsnr, EventType.EVT_NODE_FAILED, EventType.EVT_NODE_LEFT);
+
+ iteratorsHolder().tearDown();
+ }
+
+ /** */
+ protected AffinityTopologyVersion topologyVersion() {
+ return exchangeManager().readyAffinityVersion();
+ }
+
+ /** */
+ private BaseQueryContext createQueryContext(Context parent, @Nullable String schema) {
+ return BaseQueryContext.builder()
+ .parentContext(parent)
+ .frameworkConfig(
+ Frameworks.newConfigBuilder(FRAMEWORK_CONFIG)
+ .defaultSchema(schemaHolder().schema(schema))
+ .build()
+ )
+ .logger(log)
+ .build();
+ }
+
+ /** */
+ private QueryPlan prepareFragment(BaseQueryContext ctx, String jsonFragment) {
+ return new FragmentPlan(fromJson(ctx, jsonFragment));
+ }
+
+ /** {@inheritDoc} */
+ @Override public FieldsQueryCursor<List<?>> executePlan(
+ RootQuery<Row> qry,
+ QueryPlan plan
+ ) {
+ switch (plan.type()) {
+ case DML:
+ ListFieldsQueryCursor<?> cur = mapAndExecutePlan(
+ qry,
+ (MultiStepPlan)plan
+ );
+
+ cur.iterator().hasNext();
+
+ return cur;
+
+ case QUERY:
+ return mapAndExecutePlan(
+ qry,
+ (MultiStepPlan)plan
+ );
+
+ case EXPLAIN:
+ return executeExplain(qry, (ExplainPlan)plan);
+
+ case DDL:
+ return executeDdl(qry, (DdlPlan)plan);
+
+ default:
+ throw new AssertionError("Unexpected plan type: " + plan);
+ }
+ }
+
+ /** */
+ private FieldsQueryCursor<List<?>> executeDdl(RootQuery<Row> qry, DdlPlan plan) {
+ try {
+ ddlCmdHnd.handle(qry.id(), plan.command());
+ }
+ catch (IgniteCheckedException e) {
+ throw new IgniteSQLException("Failed to execute DDL statement [stmt=" + qry.sql() +
+ ", err=" + e.getMessage() + ']', e);
+ }
+ finally {
+ qryReg.unregister(qry.id());
+ }
+
+ if (plan.command() instanceof CreateTableCommand
+ && ((CreateTableCommand)plan.command()).insertStatement() != null) {
+ RootQuery<Row> insQry = qry.childQuery(schemaHolder.schema(qry.context().schemaName()));
+
+ qryReg.register(insQry);
+
+ SqlInsert insertStmt = ((CreateTableCommand)plan.command()).insertStatement();
+
+ QueryPlan dmlPlan = prepareSvc.prepareSingle(insertStmt, insQry.planningContext());
+
+ return executePlan(insQry, dmlPlan);
+ }
+ else {
+ QueryCursorImpl<List<?>> resCur = new QueryCursorImpl<>(Collections.singletonList(
+ Collections.singletonList(0L)), null, false, false);
+
+ IgniteTypeFactory typeFactory = qry.context().typeFactory();
+
+ resCur.fieldsMeta(new FieldsMetadataImpl(RelOptUtil.createDmlRowType(
+ SqlKind.INSERT, typeFactory), null).queryFieldsMetadata(typeFactory));
+
+ return resCur;
+ }
+ }
+
+ /** */
+ private ListFieldsQueryCursor<?> mapAndExecutePlan(
+ RootQuery<Row> qry,
+ MultiStepPlan plan
+ ) {
+ qry.mapping();
+
+ MappingQueryContext mapCtx = Commons.mapContext(locNodeId, topologyVersion());
+ plan.init(mappingSvc, mapCtx);
+
+ List<Fragment> fragments = plan.fragments();
+
+ // Local execution
+ Fragment fragment = F.first(fragments);
+
+ if (U.assertionsEnabled()) {
+ assert fragment != null;
+
+ FragmentMapping mapping = plan.mapping(fragment);
+
+ assert mapping != null;
+
+ List<UUID> nodes = mapping.nodeIds();
+
+ assert nodes != null && nodes.size() == 1 && F.first(nodes).equals(localNodeId());
+ }
+
+ FragmentDescription fragmentDesc = new FragmentDescription(
+ fragment.fragmentId(),
+ plan.mapping(fragment),
+ plan.target(fragment),
+ plan.remotes(fragment));
+
+ ExecutionContext<Row> ectx = new ExecutionContext<>(
+ qry.context(),
+ taskExecutor(),
+ qry.id(),
+ locNodeId,
+ locNodeId,
+ mapCtx.topologyVersion(),
+ fragmentDesc,
+ handler,
+ Commons.parametersMap(qry.parameters()));
+
+ Node<Row> node = new LogicalRelImplementor<>(ectx, partitionService(), mailboxRegistry(),
+ exchangeService(), failureProcessor()).go(fragment.root());
+
+ qry.run(ectx, plan, node);
+
+ Map<UUID, Long> fragmentsPerNode = fragments.stream()
+ .skip(1)
+ .flatMap(f -> f.mapping().nodeIds().stream())
+ .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
+
+ // Start remote execution.
+ for (int i = 1; i < fragments.size(); i++) {
+ fragment = fragments.get(i);
+ fragmentDesc = new FragmentDescription(
+ fragment.fragmentId(),
+ plan.mapping(fragment),
+ plan.target(fragment),
+ plan.remotes(fragment));
+
+ Throwable ex = null;
+ byte[] parametersMarshalled = null;
+
+ for (UUID nodeId : fragmentDesc.nodeIds()) {
+ if (ex != null)
+ qry.onResponse(nodeId, fragment.fragmentId(), ex);
+ else {
+ try {
+ QueryStartRequest req = new QueryStartRequest(
+ qry.id(),
+ qry.context().schemaName(),
+ fragment.serialized(),
+ ectx.topologyVersion(),
+ fragmentDesc,
+ fragmentsPerNode.get(nodeId).intValue(),
+ qry.parameters(),
+ parametersMarshalled
+ );
+
+ messageService().send(nodeId, req);
+
+ // Avoid marshaling of the same parameters for other nodes.
+ if (parametersMarshalled == null)
+ parametersMarshalled = req.parametersMarshalled();
+ }
+ catch (Throwable e) {
+ qry.onResponse(nodeId, fragment.fragmentId(), ex = e);
+ }
+ }
+ }
+ }
+
+ return new ListFieldsQueryCursor<>(plan, iteratorsHolder().iterator(qry.iterator()), ectx);
+ }
+
+ /** */
+ private FieldsQueryCursor<List<?>> executeExplain(RootQuery<Row> qry, ExplainPlan plan) {
+ QueryCursorImpl<List<?>> cur = new QueryCursorImpl<>(singletonList(singletonList(plan.plan())));
+ cur.fieldsMeta(plan.fieldsMeta().queryFieldsMetadata(Commons.typeFactory()));
+
+ qryReg.unregister(qry.id());
+
+ return cur;
+ }
+
+ /** */
+ private void executeFragment(Query<Row> qry, FragmentPlan plan, ExecutionContext<Row> ectx) {
+ UUID origNodeId = ectx.originatingNodeId();
+
+ Outbox<Row> node = new LogicalRelImplementor<>(
+ ectx,
+ partitionService(),
+ mailboxRegistry(),
+ exchangeService(),
+ failureProcessor()
+ )
+ .go(plan.root());
+
+ qry.addFragment(new RunningFragment<>(plan.root(), node, ectx));
+
+ node.init();
+
+ if (!qry.isExchangeWithInitNodeStarted(ectx.fragmentId())) {
+ try {
+ messageService().send(origNodeId, new QueryStartResponse(qry.id(), ectx.fragmentId()));
+ }
+ catch (IgniteCheckedException e) {
+ IgniteException wrpEx = new IgniteException("Failed to send reply. [nodeId=" + origNodeId + ']', e);
+
+ throw wrpEx;
+ }
+ }
+ }
+
+ /** */
+ private FieldsMetadata queryFieldsMetadata(PlanningContext ctx, RelDataType sqlType,
+ @Nullable List<List<String>> origins) {
+ RelDataType resultType = TypeUtils.getResultType(
+ ctx.typeFactory(), ctx.catalogReader(), sqlType, origins);
+ return new FieldsMetadataImpl(resultType, origins);
+ }
+
+ /** */
+ private void onMessage(UUID nodeId, final QueryStartRequest msg) {
+ assert nodeId != null && msg != null;
+
+ try {
+ Query<Row> qry = (Query<Row>)qryReg.register(
+ new Query<>(
+ msg.queryId(),
+ nodeId,
+ null,
+ exchangeSvc,
+ (q) -> qryReg.unregister(q.id()),
+ log,
+ msg.totalFragmentsCount()
+ )
+ );
+
+ final BaseQueryContext qctx = createQueryContext(Contexts.empty(), msg.schema());
+
+ QueryPlan qryPlan = queryPlanCache().queryPlan(
+ new CacheKey(msg.schema(), msg.root()),
+ () -> prepareFragment(qctx, msg.root())
+ );
+
+ assert qryPlan.type() == QueryPlan.Type.FRAGMENT;
+
+ ExecutionContext<Row> ectx = new ExecutionContext<>(
+ qctx,
+ taskExecutor(),
+ msg.queryId(),
+ locNodeId,
+ nodeId,
+ msg.topologyVersion(),
+ msg.fragmentDescription(),
+ handler,
+ Commons.parametersMap(msg.parameters())
+ );
+
+ executeFragment(qry, (FragmentPlan)qryPlan, ectx);
+ }
+ catch (Throwable ex) {
+ U.error(log, "Failed to start query fragment ", ex);
+
+ mailboxRegistry.outboxes(msg.queryId(), msg.fragmentId(), -1)
+ .forEach(Outbox::close);
+ mailboxRegistry.inboxes(msg.queryId(), msg.fragmentId(), -1)
+ .forEach(Inbox::close);
+
+ try {
+ messageService().send(nodeId, new QueryStartResponse(msg.queryId(), msg.fragmentId(), ex));
+ }
+ catch (IgniteCheckedException e) {
+ U.error(log, "Error occurred during send error message: " + X.getFullStackTrace(e));
+
+ IgniteException wrpEx = new IgniteException("Error occurred during send error message", e);
+
+ e.addSuppressed(ex);
+
+ Query<Row> qry = (Query<Row>)qryReg.query(msg.queryId());
+
+ qry.cancel();
+
+ throw wrpEx;
+ }
+
+ throw ex;
+ }
+ }
+
+ /** */
+ private void onMessage(UUID nodeId, QueryStartResponse msg) {
+ assert nodeId != null && msg != null;
+
+ RunningQuery qry = qryReg.query(msg.queryId());
+
+ if (qry != null) {
+ assert qry instanceof RootQuery : "Unexpected query object: " + qry;
+
+ ((RootQuery<Row>)qry).onResponse(nodeId, msg.fragmentId(), msg.error());
+ }
+ }
+
+ /** */
+ private void onMessage(UUID nodeId, ErrorMessage msg) {
+ assert nodeId != null && msg != null;
+
+ RunningQuery qry = qryReg.query(msg.queryId());
+
+ if (qry != null && qry.state() != QueryState.CLOSED) {
+ assert qry instanceof RootQuery : "Unexpected query object: " + qry;
+
+ Exception e = new RemoteException(nodeId, msg.queryId(), msg.fragmentId(), msg.error());
+
+ if (X.hasCause(msg.error(), ExecutionCancelledException.class)) {
+ e = new IgniteSQLException(
+ "The query was cancelled while executing.",
+ IgniteQueryErrorCode.QUERY_CANCELED,
+ e
+ );
+ }
+
+ ((RootQuery<Row>)qry).onError(e);
+ }
+ }
+
+ /** */
+ private void onNodeLeft(UUID nodeId) {
+ qryReg.runningQueries()
+ .forEach((qry) -> ((Query<Row>)qry).onNodeLeft(nodeId));
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/IndexScan.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/IndexScan.java
new file mode 100644
index 0000000..012070c
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/IndexScan.java
@@ -0,0 +1,318 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.ImmutableIntList;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.cluster.ClusterTopologyException;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.cache.query.index.sorted.IndexRow;
+import org.apache.ignite.internal.cache.query.index.sorted.IndexSearchRowImpl;
+import org.apache.ignite.internal.cache.query.index.sorted.InlineIndexRowHandler;
+import org.apache.ignite.internal.cache.query.index.sorted.inline.IndexQueryContext;
+import org.apache.ignite.internal.cache.query.index.sorted.inline.InlineIndex;
+import org.apache.ignite.internal.cache.query.index.sorted.keys.IndexKey;
+import org.apache.ignite.internal.cache.query.index.sorted.keys.IndexKeyFactory;
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cache.CacheObjectContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTopologyFuture;
+import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition;
+import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
+import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology;
+import org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot;
+import org.apache.ignite.internal.processors.query.calcite.exec.RowHandler.RowFactory;
+import org.apache.ignite.internal.processors.query.calcite.schema.CacheTableDescriptor;
+import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
+import org.apache.ignite.internal.processors.query.calcite.util.TypeUtils;
+import org.apache.ignite.internal.util.lang.GridCursor;
+import org.apache.ignite.spi.indexing.IndexingQueryFilter;
+import org.apache.ignite.spi.indexing.IndexingQueryFilterImpl;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Scan on index.
+ */
+public class IndexScan<Row> extends AbstractIndexScan<Row, IndexRow> {
+ /** */
+ private final GridKernalContext kctx;
+
+ /** */
+ private final GridCacheContext<?, ?> cctx;
+
+ /** */
+ private final CacheObjectContext coCtx;
+
+ /** */
+ private final CacheTableDescriptor desc;
+
+ /** */
+ private final RowFactory<Row> factory;
+
+ /** */
+ private final AffinityTopologyVersion topVer;
+
+ /** */
+ private final int[] parts;
+
+ /** */
+ private final MvccSnapshot mvccSnapshot;
+
+ /** */
+ private volatile List<GridDhtLocalPartition> reserved;
+
+ /** */
+ private final ImmutableBitSet requiredColumns;
+
+ /** */
+ private final InlineIndex idx;
+
+ /** Mapping from index keys to row fields. */
+ private final ImmutableIntList idxFieldMapping;
+
+ /** Types of key fields stored in index. */
+ private final Type[] fieldsStoreTypes;
+
+ /**
+ * @param ectx Execution context.
+ * @param desc Table descriptor.
+ * @param idxFieldMapping Mapping from index keys to row fields.
+ * @param idx Phisycal index.
+ * @param filters Additional filters.
+ * @param lowerBound Lower index scan bound.
+ * @param upperBound Upper index scan bound.
+ */
+ public IndexScan(
+ ExecutionContext<Row> ectx,
+ CacheTableDescriptor desc,
+ InlineIndex idx,
+ ImmutableIntList idxFieldMapping,
+ int[] parts,
+ Predicate<Row> filters,
+ Supplier<Row> lowerBound,
+ Supplier<Row> upperBound,
+ Function<Row, Row> rowTransformer,
+ @Nullable ImmutableBitSet requiredColumns
+ ) {
+ super(
+ ectx,
+ desc.rowType(ectx.getTypeFactory(), requiredColumns),
+ new TreeIndexWrapper(idx),
+ filters,
+ lowerBound,
+ upperBound,
+ rowTransformer
+ );
+
+ this.desc = desc;
+ this.idx = idx;
+ cctx = desc.cacheContext();
+ kctx = cctx.kernalContext();
+ coCtx = cctx.cacheObjectContext();
+
+ factory = ectx.rowHandler().factory(ectx.getTypeFactory(), rowType);
+ topVer = ectx.topologyVersion();
+ this.parts = parts;
+ mvccSnapshot = ectx.mvccSnapshot();
+ this.requiredColumns = requiredColumns;
+ this.idxFieldMapping = idxFieldMapping;
+
+ RelDataType srcRowType = desc.rowType(ectx.getTypeFactory(), null);
+ IgniteTypeFactory typeFactory = ectx.getTypeFactory();
+ fieldsStoreTypes = new Type[srcRowType.getFieldCount()];
+
+ for (int i = 0; i < srcRowType.getFieldCount(); i++)
+ fieldsStoreTypes[i] = typeFactory.getResultClass(srcRowType.getFieldList().get(i).getType());
+ }
+
+ /** {@inheritDoc} */
+ @Override public synchronized Iterator<Row> iterator() {
+ reserve();
+
+ try {
+ return super.iterator();
+ }
+ catch (Exception e) {
+ release();
+
+ throw e;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override protected IndexRow row2indexRow(Row bound) {
+ if (bound == null)
+ return null;
+
+ InlineIndexRowHandler idxRowHnd = idx.segment(0).rowHandler();
+ RowHandler<Row> rowHnd = ectx.rowHandler();
+
+ IndexKey[] keys = new IndexKey[idxRowHnd.indexKeyDefinitions().size()];
+
+ assert keys.length >= idxFieldMapping.size() : "Unexpected index keys [keys.length=" + keys.length +
+ ", idxFieldMapping.size()=" + idxFieldMapping.size() + ']';
+
+ boolean nullSearchRow = true;
+
+ for (int i = 0; i < idxFieldMapping.size(); ++i) {
+ int fieldIdx = idxFieldMapping.getInt(i);
+ Object key = rowHnd.get(fieldIdx, bound);
+
+ if (key != ectx.unspecifiedValue()) {
+ key = TypeUtils.fromInternal(ectx, key, fieldsStoreTypes[fieldIdx]);
+
+ keys[i] = IndexKeyFactory.wrap(key, idxRowHnd.indexKeyDefinitions().get(i).idxType(),
+ cctx.cacheObjectContext(), idxRowHnd.indexKeyTypeSettings());
+
+ nullSearchRow = false;
+ }
+ }
+
+ return nullSearchRow ? null : new IndexSearchRowImpl(keys, idxRowHnd);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected Row indexRow2Row(IndexRow row) throws IgniteCheckedException {
+ return desc.toRow(ectx, row.cacheDataRow(), factory, requiredColumns);
+ }
+
+ /** */
+ @Override public void close() {
+ release();
+ }
+
+ /** */
+ private synchronized void reserve() {
+ if (reserved != null)
+ return;
+
+ GridDhtPartitionTopology top = cctx.topology();
+ top.readLock();
+
+ GridDhtTopologyFuture topFut = top.topologyVersionFuture();
+
+ boolean done = topFut.isDone();
+
+ if (!done || !(topFut.topologyVersion().compareTo(topVer) >= 0
+ && cctx.shared().exchange().lastAffinityChangedTopologyVersion(topFut.initialVersion()).compareTo(topVer) <= 0)) {
+ top.readUnlock();
+
+ throw new ClusterTopologyException("Topology was changed. Please retry on stable topology.");
+ }
+
+ List<GridDhtLocalPartition> toReserve;
+
+ if (cctx.isReplicated()) {
+ int partsCnt = cctx.affinity().partitions();
+ toReserve = new ArrayList<>(partsCnt);
+ for (int i = 0; i < partsCnt; i++)
+ toReserve.add(top.localPartition(i));
+ }
+ else if (cctx.isPartitioned()) {
+ assert parts != null;
+
+ toReserve = new ArrayList<>(parts.length);
+ for (int i = 0; i < parts.length; i++)
+ toReserve.add(top.localPartition(parts[i]));
+ }
+ else {
+ assert cctx.isLocal();
+
+ toReserve = Collections.emptyList();
+ }
+
+ reserved = new ArrayList<>(toReserve.size());
+
+ try {
+ for (GridDhtLocalPartition part : toReserve) {
+ if (part == null || !part.reserve()) {
+ throw new ClusterTopologyException(
+ "Failed to reserve partition for query execution. Retry on stable topology."
+ );
+ }
+ else if (part.state() != GridDhtPartitionState.OWNING) {
+ part.release();
+
+ throw new ClusterTopologyException(
+ "Failed to reserve partition for query execution. Retry on stable topology."
+ );
+ }
+
+ reserved.add(part);
+ }
+ }
+ catch (Exception e) {
+ release();
+
+ throw e;
+ }
+ finally {
+ top.readUnlock();
+ }
+ }
+
+ /** */
+ private synchronized void release() {
+ if (reserved == null)
+ return;
+
+ for (GridDhtLocalPartition part : reserved)
+ part.release();
+
+ reserved = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected IndexQueryContext indexQueryContext() {
+ IndexingQueryFilter filter = new IndexingQueryFilterImpl(kctx, topVer, parts);
+ return new IndexQueryContext(filter, null, mvccSnapshot);
+ }
+
+ /** */
+ private static class TreeIndexWrapper implements TreeIndex<IndexRow> {
+ /** Underlying index. */
+ private final InlineIndex idx;
+
+ /** */
+ private TreeIndexWrapper(InlineIndex idx) {
+ this.idx = idx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public GridCursor<IndexRow> find(IndexRow lower, IndexRow upper, IndexQueryContext qctx) {
+ try {
+ int seg = 0; // TODO segments support
+
+ return idx.find(lower, upper, true, true, seg, qctx);
+ }
+ catch (IgniteCheckedException e) {
+ throw new IgniteException("Failed to find index rows", e);
+ }
+ }
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementor.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementor.java
new file mode 100644
index 0000000..17be8cb
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/LogicalRelImplementor.java
@@ -0,0 +1,775 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Intersect;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.Minus;
+import org.apache.calcite.rel.core.Spool;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.ignite.internal.processors.failure.FailureProcessor;
+import org.apache.ignite.internal.processors.query.calcite.exec.RowHandler.RowFactory;
+import org.apache.ignite.internal.processors.query.calcite.exec.exp.ExpressionFactory;
+import org.apache.ignite.internal.processors.query.calcite.exec.exp.agg.AccumulatorWrapper;
+import org.apache.ignite.internal.processors.query.calcite.exec.exp.agg.AggregateType;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.AbstractSetOpNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.CorrelatedNestedLoopJoinNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.FilterNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.HashAggregateNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Inbox;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.IndexSpoolNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.IntersectNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.LimitNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.MergeJoinNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.MinusNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.ModifyNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.NestedLoopJoinNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Node;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Outbox;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.ProjectNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.ScanNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.SortAggregateNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.SortNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.TableSpoolNode;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.UnionAllNode;
+import org.apache.ignite.internal.processors.query.calcite.metadata.AffinityService;
+import org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGroup;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteCorrelatedNestedLoopJoin;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteExchange;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteFilter;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteHashIndexSpool;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexScan;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteLimit;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteMergeJoin;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteNestedLoopJoin;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteProject;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteReceiver;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRel;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteRelVisitor;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSender;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSort;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSortedIndexSpool;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableFunctionScan;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableModify;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableScan;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTableSpool;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteTrimExchange;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteUnionAll;
+import org.apache.ignite.internal.processors.query.calcite.rel.IgniteValues;
+import org.apache.ignite.internal.processors.query.calcite.rel.agg.IgniteColocatedHashAggregate;
+import org.apache.ignite.internal.processors.query.calcite.rel.agg.IgniteColocatedSortAggregate;
+import org.apache.ignite.internal.processors.query.calcite.rel.agg.IgniteMapHashAggregate;
+import org.apache.ignite.internal.processors.query.calcite.rel.agg.IgniteMapSortAggregate;
+import org.apache.ignite.internal.processors.query.calcite.rel.agg.IgniteReduceHashAggregate;
+import org.apache.ignite.internal.processors.query.calcite.rel.agg.IgniteReduceSortAggregate;
+import org.apache.ignite.internal.processors.query.calcite.rel.set.IgniteSetOp;
+import org.apache.ignite.internal.processors.query.calcite.rule.LogicalScanConverterRule;
+import org.apache.ignite.internal.processors.query.calcite.schema.CacheTableDescriptor;
+import org.apache.ignite.internal.processors.query.calcite.schema.IgniteIndex;
+import org.apache.ignite.internal.processors.query.calcite.schema.IgniteTable;
+import org.apache.ignite.internal.processors.query.calcite.trait.Destination;
+import org.apache.ignite.internal.processors.query.calcite.trait.IgniteDistribution;
+import org.apache.ignite.internal.processors.query.calcite.trait.TraitUtils;
+import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
+import org.apache.ignite.internal.processors.query.calcite.util.Commons;
+import org.apache.ignite.internal.processors.query.calcite.util.RexUtils;
+import org.apache.ignite.internal.util.typedef.F;
+
+import static org.apache.calcite.rel.RelDistribution.Type.HASH_DISTRIBUTED;
+import static org.apache.ignite.internal.processors.query.calcite.util.TypeUtils.combinedRowType;
+
+/**
+ * Implements a query plan.
+ */
+@SuppressWarnings("TypeMayBeWeakened")
+public class LogicalRelImplementor<Row> implements IgniteRelVisitor<Node<Row>> {
+ /** */
+ public static final String CNLJ_NOT_SUPPORTED_JOIN_ASSERTION_MSG = "only INNER and LEFT join supported by IgniteCorrelatedNestedLoop";
+
+ /** */
+ private final ExecutionContext<Row> ctx;
+
+ /** */
+ private final AffinityService affSrvc;
+
+ /** */
+ private final ExchangeService exchangeSvc;
+
+ /** */
+ private final MailboxRegistry mailboxRegistry;
+
+ /** */
+ private final ExpressionFactory<Row> expressionFactory;
+
+ /**
+ * @param ctx Root context.
+ * @param affSrvc Affinity service.
+ * @param mailboxRegistry Mailbox registry.
+ * @param exchangeSvc Exchange service.
+ * @param failure Failure processor.
+ */
+ public LogicalRelImplementor(
+ ExecutionContext<Row> ctx,
+ AffinityService affSrvc,
+ MailboxRegistry mailboxRegistry,
+ ExchangeService exchangeSvc,
+ FailureProcessor failure
+ ) {
+ this.affSrvc = affSrvc;
+ this.mailboxRegistry = mailboxRegistry;
+ this.exchangeSvc = exchangeSvc;
+ this.ctx = ctx;
+
+ expressionFactory = ctx.expressionFactory();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteSender rel) {
+ IgniteDistribution distribution = rel.distribution();
+
+ Destination<Row> dest = distribution.destination(ctx, affSrvc, ctx.target());
+
+ // Outbox fragment ID is used as exchange ID as well.
+ Outbox<Row> outbox =
+ new Outbox<>(ctx, rel.getRowType(), exchangeSvc, mailboxRegistry, rel.exchangeId(), rel.targetFragmentId(), dest);
+
+ Node<Row> input = visit(rel.getInput());
+
+ outbox.register(input);
+
+ mailboxRegistry.register(outbox);
+
+ return outbox;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteFilter rel) {
+ Predicate<Row> pred = expressionFactory.predicate(rel.getCondition(), rel.getRowType());
+
+ FilterNode<Row> node = new FilterNode<>(ctx, rel.getRowType(), pred);
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteTrimExchange rel) {
+ assert TraitUtils.distribution(rel).getType() == HASH_DISTRIBUTED;
+
+ IgniteDistribution distr = rel.distribution();
+ Destination<Row> dest = distr.destination(ctx, affSrvc, ctx.group(rel.sourceId()));
+ UUID localNodeId = ctx.localNodeId();
+
+ FilterNode<Row> node = new FilterNode<>(ctx, rel.getRowType(), r -> Objects.equals(localNodeId, F.first(dest.targets(r))));
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteProject rel) {
+ Function<Row, Row> prj = expressionFactory.project(rel.getProjects(), rel.getInput().getRowType());
+
+ ProjectNode<Row> node = new ProjectNode<>(ctx, rel.getRowType(), prj);
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteNestedLoopJoin rel) {
+ RelDataType outType = rel.getRowType();
+ RelDataType leftType = rel.getLeft().getRowType();
+ RelDataType rightType = rel.getRight().getRowType();
+ JoinRelType joinType = rel.getJoinType();
+
+ RelDataType rowType = combinedRowType(ctx.getTypeFactory(), leftType, rightType);
+
+ BiPredicate<Row, Row> cond = expressionFactory.biPredicate(rel.getCondition(), rowType);
+
+ Node<Row> node = NestedLoopJoinNode.create(ctx, outType, leftType, rightType, joinType, cond);
+
+ Node<Row> leftInput = visit(rel.getLeft());
+ Node<Row> rightInput = visit(rel.getRight());
+
+ node.register(F.asList(leftInput, rightInput));
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteCorrelatedNestedLoopJoin rel) {
+ RelDataType outType = rel.getRowType();
+ RelDataType leftType = rel.getLeft().getRowType();
+ RelDataType rightType = rel.getRight().getRowType();
+
+ RelDataType rowType = combinedRowType(ctx.getTypeFactory(), leftType, rightType);
+ BiPredicate<Row, Row> cond = expressionFactory.biPredicate(rel.getCondition(), rowType);
+
+ assert rel.getJoinType() == JoinRelType.INNER || rel.getJoinType() == JoinRelType.LEFT
+ : CNLJ_NOT_SUPPORTED_JOIN_ASSERTION_MSG;
+
+ Node<Row> node = new CorrelatedNestedLoopJoinNode<>(ctx, outType, cond, rel.getVariablesSet(),
+ rel.getJoinType());
+
+ Node<Row> leftInput = visit(rel.getLeft());
+ Node<Row> rightInput = visit(rel.getRight());
+
+ node.register(F.asList(leftInput, rightInput));
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteMergeJoin rel) {
+ RelDataType outType = rel.getRowType();
+ RelDataType leftType = rel.getLeft().getRowType();
+ RelDataType rightType = rel.getRight().getRowType();
+ JoinRelType joinType = rel.getJoinType();
+
+ int pairsCnt = rel.analyzeCondition().pairs().size();
+
+ Comparator<Row> comp = expressionFactory.comparator(
+ rel.leftCollation().getFieldCollations().subList(0, pairsCnt),
+ rel.rightCollation().getFieldCollations().subList(0, pairsCnt)
+ );
+
+ Node<Row> node = MergeJoinNode.create(ctx, outType, leftType, rightType, joinType, comp);
+
+ Node<Row> leftInput = visit(rel.getLeft());
+ Node<Row> rightInput = visit(rel.getRight());
+
+ node.register(F.asList(leftInput, rightInput));
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteIndexScan rel) {
+ RexNode condition = rel.condition();
+ List<RexNode> projects = rel.projects();
+
+ IgniteTable tbl = rel.getTable().unwrap(IgniteTable.class);
+ IgniteTypeFactory typeFactory = ctx.getTypeFactory();
+
+ ImmutableBitSet requiredColumns = rel.requiredColumns();
+ List<RexNode> lowerCond = rel.lowerBound();
+ List<RexNode> upperCond = rel.upperBound();
+
+ RelDataType rowType = tbl.getRowType(typeFactory, requiredColumns);
+
+ Predicate<Row> filters = condition == null ? null : expressionFactory.predicate(condition, rowType);
+ Supplier<Row> lower = lowerCond == null ? null : expressionFactory.rowSource(lowerCond);
+ Supplier<Row> upper = upperCond == null ? null : expressionFactory.rowSource(upperCond);
+ Function<Row, Row> prj = projects == null ? null : expressionFactory.project(projects, rowType);
+
+ ColocationGroup grp = ctx.group(rel.sourceId());
+
+ IgniteIndex idx = tbl.getIndex(rel.indexName());
+
+ if (idx != null && !tbl.isIndexRebuildInProgress()) {
+ Iterable<Row> rowsIter = idx.scan(ctx, grp, filters, lower, upper, prj, requiredColumns);
+
+ return new ScanNode<>(ctx, rowType, rowsIter);
+ }
+ else {
+ // Index was invalidated after planning, workaround through table-scan -> sort -> index spool.
+ // If there are correlates in filter or project, spool node is required to provide ability to rewind input.
+ // Sort node is required if output should be sorted or if spool node required (to provide search by
+ // index conditions).
+ // Additionally, project node is required in case of spool inserted, since spool requires unmodified
+ // original input for filtering by index conditions.
+ boolean filterHasCorrelation = condition != null && RexUtils.hasCorrelation(condition);
+ boolean projectHasCorrelation = projects != null && RexUtils.hasCorrelation(projects);
+ boolean spoolNodeRequired = projectHasCorrelation || filterHasCorrelation;
+ boolean projNodeRequired = projects != null && spoolNodeRequired;
+
+ Iterable<Row> rowsIter = tbl.scan(
+ ctx,
+ grp,
+ filterHasCorrelation ? null : filters,
+ projNodeRequired ? null : prj,
+ requiredColumns
+ );
+
+ // If there are projects in the scan node - after the scan we already have target row type.
+ if (!spoolNodeRequired && projects != null)
+ rowType = rel.getRowType();
+
+ Node<Row> node = new ScanNode<>(ctx, rowType, rowsIter);
+
+ RelCollation collation = rel.collation();
+
+ if ((!spoolNodeRequired && projects != null) || requiredColumns != null) {
+ collation = collation.apply(LogicalScanConverterRule.createMapping(
+ spoolNodeRequired ? null : projects,
+ requiredColumns,
+ tbl.getRowType(typeFactory).getFieldCount()
+ ));
+ }
+
+ boolean sortNodeRequired = !collation.getFieldCollations().isEmpty();
+
+ if (sortNodeRequired) {
+ SortNode<Row> sortNode = new SortNode<>(ctx, rowType, expressionFactory.comparator(collation));
+
+ sortNode.register(node);
+
+ node = sortNode;
+ }
+
+ if (spoolNodeRequired) {
+ if (lowerCond != null || upperCond != null) {
+ if (requiredColumns != null) {
+ // Remap index find predicate according to rowType of the spool.
+ int cardinality = requiredColumns.cardinality();
+ List<RexNode> remappedLowerCond = lowerCond != null ? new ArrayList<>(cardinality) : null;
+ List<RexNode> remappedUpperCond = upperCond != null ? new ArrayList<>(cardinality) : null;
+
+ for (int i = requiredColumns.nextSetBit(0); i != -1; i = requiredColumns.nextSetBit(i + 1)) {
+ if (remappedLowerCond != null)
+ remappedLowerCond.add(lowerCond.get(i));
+
+ if (remappedUpperCond != null)
+ remappedUpperCond.add(upperCond.get(i));
+ }
+
+ lower = remappedLowerCond == null ? null : expressionFactory.rowSource(remappedLowerCond);
+ upper = remappedUpperCond == null ? null : expressionFactory.rowSource(remappedUpperCond);
+ }
+ }
+
+ IndexSpoolNode<Row> spoolNode = IndexSpoolNode.createTreeSpool(
+ ctx,
+ rowType,
+ collation,
+ expressionFactory.comparator(collation),
+ filterHasCorrelation ? filters : null, // Not correlated filter included into table scan.
+ lower,
+ upper
+ );
+
+ spoolNode.register(node);
+
+ node = spoolNode;
+ }
+
+ if (projNodeRequired) {
+ ProjectNode<Row> projectNode = new ProjectNode<>(ctx, rel.getRowType(), prj);
+
+ projectNode.register(node);
+
+ node = projectNode;
+ }
+
+ return node;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteTableScan rel) {
+ RexNode condition = rel.condition();
+ List<RexNode> projects = rel.projects();
+ ImmutableBitSet requiredColunms = rel.requiredColumns();
+
+ IgniteTable tbl = rel.getTable().unwrap(IgniteTable.class);
+ IgniteTypeFactory typeFactory = ctx.getTypeFactory();
+
+ RelDataType rowType = tbl.getRowType(typeFactory, requiredColunms);
+
+ Predicate<Row> filters = condition == null ? null : expressionFactory.predicate(condition, rowType);
+ Function<Row, Row> prj = projects == null ? null : expressionFactory.project(projects, rowType);
+
+ ColocationGroup group = ctx.group(rel.sourceId());
+
+ Iterable<Row> rowsIter = tbl.scan(ctx, group, filters, prj, requiredColunms);
+
+ return new ScanNode<>(ctx, rowType, rowsIter);
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteValues rel) {
+ List<RexLiteral> vals = Commons.flat(Commons.cast(rel.getTuples()));
+
+ RelDataType rowType = rel.getRowType();
+
+ return new ScanNode<>(ctx, rowType, expressionFactory.values(vals, rowType));
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteUnionAll rel) {
+ UnionAllNode<Row> node = new UnionAllNode<>(ctx, rel.getRowType());
+
+ List<Node<Row>> inputs = Commons.transform(rel.getInputs(), this::visit);
+
+ node.register(inputs);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteLimit rel) {
+ Supplier<Integer> offset = (rel.offset() == null) ? null : expressionFactory.execute(rel.offset());
+ Supplier<Integer> fetch = (rel.fetch() == null) ? null : expressionFactory.execute(rel.fetch());
+
+ LimitNode<Row> node = new LimitNode<>(ctx, rel.getRowType(), offset, fetch);
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteSort rel) {
+ RelCollation collation = rel.getCollation();
+
+ SortNode<Row> node = new SortNode<>(ctx, rel.getRowType(), expressionFactory.comparator(collation));
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteTableSpool rel) {
+ TableSpoolNode<Row> node = new TableSpoolNode<>(ctx, rel.getRowType(), rel.readType == Spool.Type.LAZY);
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteSortedIndexSpool rel) {
+ RelCollation collation = rel.collation();
+
+ assert rel.indexCondition() != null : rel;
+
+ List<RexNode> lowerBound = rel.indexCondition().lowerBound();
+ List<RexNode> upperBound = rel.indexCondition().upperBound();
+
+ Predicate<Row> filter = expressionFactory.predicate(rel.condition(), rel.getRowType());
+ Supplier<Row> lower = lowerBound == null ? null : expressionFactory.rowSource(lowerBound);
+ Supplier<Row> upper = upperBound == null ? null : expressionFactory.rowSource(upperBound);
+
+ IndexSpoolNode<Row> node = IndexSpoolNode.createTreeSpool(
+ ctx,
+ rel.getRowType(),
+ collation,
+ expressionFactory.comparator(collation),
+ filter,
+ lower,
+ upper
+ );
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteHashIndexSpool rel) {
+ Supplier<Row> searchRow = expressionFactory.rowSource(rel.searchRow());
+
+ Predicate<Row> filter = expressionFactory.predicate(rel.condition(), rel.getRowType());
+
+ IndexSpoolNode<Row> node = IndexSpoolNode.createHashSpool(
+ ctx,
+ rel.getRowType(),
+ ImmutableBitSet.of(rel.keys()),
+ filter,
+ searchRow
+ );
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteSetOp rel) {
+ RelDataType rowType = rel.getRowType();
+
+ RowFactory<Row> rowFactory = ctx.rowHandler().factory(ctx.getTypeFactory(), rowType);
+
+ List<Node<Row>> inputs = Commons.transform(rel.getInputs(), this::visit);
+
+ AbstractSetOpNode<Row> node;
+
+ if (rel instanceof Minus)
+ node = new MinusNode<>(ctx, rowType, rel.aggregateType(), rel.all(), rowFactory);
+ else if (rel instanceof Intersect)
+ node = new IntersectNode<>(ctx, rowType, rel.aggregateType(), rel.all(), rowFactory, rel.getInputs().size());
+ else
+ throw new AssertionError();
+
+ node.register(inputs);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteTableFunctionScan rel) {
+ Supplier<Iterable<Object[]>> dataSupplier = expressionFactory.execute(rel.getCall());
+
+ RelDataType rowType = rel.getRowType();
+
+ RowFactory<Row> rowFactory = ctx.rowHandler().factory(ctx.getTypeFactory(), rowType);
+
+ return new ScanNode<>(ctx, rowType, new TableFunctionScan<>(dataSupplier, rowFactory));
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteTableModify rel) {
+ switch (rel.getOperation()) {
+ case INSERT:
+ case UPDATE:
+ case DELETE:
+ case MERGE:
+ ModifyNode<Row> node = new ModifyNode<>(ctx, rel.getRowType(), rel.getTable().unwrap(CacheTableDescriptor.class),
+ rel.getOperation(), rel.getUpdateColumnList());
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteReceiver rel) {
+ Inbox<Row> inbox = (Inbox<Row>)mailboxRegistry.register(
+ new Inbox<>(ctx, exchangeSvc, mailboxRegistry, rel.exchangeId(), rel.sourceFragmentId()));
+
+ // here may be an already created (to consume rows from remote nodes) inbox
+ // without proper context, we need to init it with a right one.
+ inbox.init(ctx, rel.getRowType(), ctx.remotes(rel.exchangeId()), expressionFactory.comparator(rel.collation()));
+
+ return inbox;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteColocatedHashAggregate rel) {
+ AggregateType type = AggregateType.SINGLE;
+
+ RelDataType rowType = rel.getRowType();
+ RelDataType inputType = rel.getInput().getRowType();
+
+ Supplier<List<AccumulatorWrapper<Row>>> accFactory = expressionFactory.accumulatorsFactory(
+ type, rel.getAggCallList(), inputType);
+ RowFactory<Row> rowFactory = ctx.rowHandler().factory(ctx.getTypeFactory(), rowType);
+
+ HashAggregateNode<Row> node = new HashAggregateNode<>(ctx, rowType, type, rel.getGroupSets(), accFactory, rowFactory);
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteMapHashAggregate rel) {
+ AggregateType type = AggregateType.MAP;
+
+ RelDataType rowType = rel.getRowType();
+ RelDataType inputType = rel.getInput().getRowType();
+
+ Supplier<List<AccumulatorWrapper<Row>>> accFactory = expressionFactory.accumulatorsFactory(
+ type, rel.getAggCallList(), inputType);
+ RowFactory<Row> rowFactory = ctx.rowHandler().factory(ctx.getTypeFactory(), rowType);
+
+ HashAggregateNode<Row> node = new HashAggregateNode<>(ctx, rowType, type, rel.getGroupSets(), accFactory, rowFactory);
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteReduceHashAggregate rel) {
+ AggregateType type = AggregateType.REDUCE;
+
+ RelDataType rowType = rel.getRowType();
+
+ Supplier<List<AccumulatorWrapper<Row>>> accFactory = expressionFactory.accumulatorsFactory(
+ type, rel.getAggregateCalls(), null);
+ RowFactory<Row> rowFactory = ctx.rowHandler().factory(ctx.getTypeFactory(), rowType);
+
+ HashAggregateNode<Row> node = new HashAggregateNode<>(ctx, rowType, type, rel.getGroupSets(), accFactory, rowFactory);
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteColocatedSortAggregate rel) {
+ AggregateType type = AggregateType.SINGLE;
+
+ RelDataType rowType = rel.getRowType();
+ RelDataType inputType = rel.getInput().getRowType();
+
+ Supplier<List<AccumulatorWrapper<Row>>> accFactory = expressionFactory.accumulatorsFactory(
+ type,
+ rel.getAggCallList(),
+ inputType
+ );
+
+ RowFactory<Row> rowFactory = ctx.rowHandler().factory(ctx.getTypeFactory(), rowType);
+
+ SortAggregateNode<Row> node = new SortAggregateNode<>(
+ ctx,
+ rowType,
+ type,
+ rel.getGroupSet(),
+ accFactory,
+ rowFactory,
+ expressionFactory.comparator(rel.collation())
+ );
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteMapSortAggregate rel) {
+ AggregateType type = AggregateType.MAP;
+
+ RelDataType rowType = rel.getRowType();
+ RelDataType inputType = rel.getInput().getRowType();
+
+ Supplier<List<AccumulatorWrapper<Row>>> accFactory = expressionFactory.accumulatorsFactory(
+ type,
+ rel.getAggCallList(),
+ inputType
+ );
+
+ RowFactory<Row> rowFactory = ctx.rowHandler().factory(ctx.getTypeFactory(), rowType);
+
+ SortAggregateNode<Row> node = new SortAggregateNode<>(
+ ctx,
+ rowType,
+ type,
+ rel.getGroupSet(),
+ accFactory,
+ rowFactory,
+ expressionFactory.comparator(rel.collation())
+ );
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteReduceSortAggregate rel) {
+ AggregateType type = AggregateType.REDUCE;
+
+ RelDataType rowType = rel.getRowType();
+
+ Supplier<List<AccumulatorWrapper<Row>>> accFactory = expressionFactory.accumulatorsFactory(
+ type,
+ rel.getAggregateCalls(),
+ null
+ );
+
+ RowFactory<Row> rowFactory = ctx.rowHandler().factory(ctx.getTypeFactory(), rowType);
+
+ SortAggregateNode<Row> node = new SortAggregateNode<>(
+ ctx,
+ rowType,
+ type,
+ rel.getGroupSet(),
+ accFactory,
+ rowFactory,
+ expressionFactory.comparator(rel.collation())
+ );
+
+ Node<Row> input = visit(rel.getInput());
+
+ node.register(input);
+
+ return node;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteRel rel) {
+ return rel.accept(this);
+ }
+
+ /** {@inheritDoc} */
+ @Override public Node<Row> visit(IgniteExchange rel) {
+ throw new AssertionError();
+ }
+
+ /** */
+ private Node<Row> visit(RelNode rel) {
+ return visit((IgniteRel)rel);
+ }
+
+ /** */
+ public <T extends Node<Row>> T go(IgniteRel rel) {
+ return (T)visit(rel);
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/MailboxRegistry.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/MailboxRegistry.java
new file mode 100644
index 0000000..8c7c2d4
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/MailboxRegistry.java
@@ -0,0 +1,100 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.Collection;
+import java.util.UUID;
+
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Inbox;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Outbox;
+import org.apache.ignite.internal.processors.query.calcite.util.Service;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ *
+ */
+public interface MailboxRegistry extends Service {
+ /**
+ * Tries to register and inbox node and returns it if success or returns previously registered inbox otherwise.
+ *
+ * @param inbox Inbox.
+ * @return Registered inbox.
+ */
+ Inbox<?> register(Inbox<?> inbox);
+
+ /**
+ * Unregisters an inbox.
+ *
+ * @param inbox Inbox to unregister.
+ */
+ void unregister(Inbox<?> inbox);
+
+ /**
+ * Registers an outbox.
+ *
+ * @param outbox Outbox to register.
+ */
+ void register(Outbox<?> outbox);
+
+ /**
+ * Unregisters an outbox.
+ *
+ * @param outbox Outbox to unregister.
+ */
+ void unregister(Outbox<?> outbox);
+
+ /**
+ * Returns a registered outbox by provided query ID, exchange ID pair.
+ *
+ * @param qryId Query ID.
+ * @param exchangeId Exchange ID.
+ *
+ * @return Registered outbox. May be {@code null} if execution was cancelled.
+ */
+ Outbox<?> outbox(UUID qryId, long exchangeId);
+
+ /**
+ * Returns a registered inbox by provided query ID, exchange ID pair.
+ *
+ * @param qryId Query ID.
+ * @param exchangeId Exchange ID.
+ *
+ * @return Registered inbox. May be {@code null} if execution was cancelled.
+ */
+ Inbox<?> inbox(UUID qryId, long exchangeId);
+
+ /**
+ * Returns all registered inboxes for provided query ID.
+ *
+ * @param qryId Query ID. {@code null} means return inboxes with any query id.
+ * @param fragmentId Fragment Id. {@code -1} means return inboxes with any fragment id.
+ * @param exchangeId Exchange Id. {@code -1} means return inboxes with any exchange id.
+ * @return Registered inboxes.
+ */
+ Collection<Inbox<?>> inboxes(@Nullable UUID qryId, long fragmentId, long exchangeId);
+
+ /**
+ * Returns all registered outboxes for provided query ID.
+ *
+ * @param qryId Query ID. {@code null} means return outboxes with any query id.
+ * @param fragmentId Fragment Id. {@code -1} means return outboxes with any fragment id.
+ * @param exchangeId Exchange Id. {@code -1} means return outboxes with any exchange id.
+ * @return Registered outboxes.
+ */
+ Collection<Outbox<?>> outboxes(@Nullable UUID qryId, long fragmentId, long exchangeId);
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/MailboxRegistryImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/MailboxRegistryImpl.java
new file mode 100644
index 0000000..538e7b0
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/MailboxRegistryImpl.java
@@ -0,0 +1,216 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.apache.ignite.events.EventType;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.managers.eventstorage.DiscoveryEventListener;
+import org.apache.ignite.internal.managers.eventstorage.GridEventStorageManager;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Inbox;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Mailbox;
+import org.apache.ignite.internal.processors.query.calcite.exec.rel.Outbox;
+import org.apache.ignite.internal.processors.query.calcite.util.AbstractService;
+import org.apache.ignite.internal.util.tostring.GridToStringExclude;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ *
+ */
+public class MailboxRegistryImpl extends AbstractService implements MailboxRegistry {
+ /** */
+ private static final Predicate<Mailbox<?>> ALWAYS_TRUE = o -> true;
+
+ /** */
+ private final Map<MailboxKey, Outbox<?>> locals;
+
+ /** */
+ private final Map<MailboxKey, Inbox<?>> remotes;
+
+ /** */
+ @GridToStringExclude
+ private final DiscoveryEventListener discoLsnr;
+
+ /** */
+ @GridToStringExclude
+ private GridEventStorageManager evtMgr;
+
+ /**
+ * @param ctx Kernal.
+ */
+ public MailboxRegistryImpl(GridKernalContext ctx) {
+ super(ctx);
+
+ locals = new ConcurrentHashMap<>();
+ remotes = new ConcurrentHashMap<>();
+
+ discoLsnr = (e, c) -> onNodeLeft(e.eventNode().id());
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onStart(GridKernalContext ctx) {
+ eventManager(ctx.event());
+
+ init();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void init() {
+ eventManager().addDiscoveryEventListener(discoLsnr, EventType.EVT_NODE_FAILED, EventType.EVT_NODE_LEFT);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void tearDown() {
+ eventManager().removeDiscoveryEventListener(discoLsnr, EventType.EVT_NODE_FAILED, EventType.EVT_NODE_LEFT);
+ }
+
+ /** {@inheritDoc} */
+ @Override public Inbox<?> register(Inbox<?> inbox) {
+ Inbox<?> old = remotes.putIfAbsent(new MailboxKey(inbox.queryId(), inbox.exchangeId()), inbox);
+
+ return old != null ? old : inbox;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void unregister(Inbox<?> inbox) {
+ remotes.remove(new MailboxKey(inbox.queryId(), inbox.exchangeId()), inbox);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void register(Outbox<?> outbox) {
+ Outbox<?> res = locals.put(new MailboxKey(outbox.queryId(), outbox.exchangeId()), outbox);
+
+ assert res == null : res;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void unregister(Outbox<?> outbox) {
+ locals.remove(new MailboxKey(outbox.queryId(), outbox.exchangeId()), outbox);
+ }
+
+ /** {@inheritDoc} */
+ @Override public Outbox<?> outbox(UUID qryId, long exchangeId) {
+ return locals.get(new MailboxKey(qryId, exchangeId));
+ }
+
+ /** {@inheritDoc} */
+ @Override public Inbox<?> inbox(UUID qryId, long exchangeId) {
+ return remotes.get(new MailboxKey(qryId, exchangeId));
+ }
+
+ /** {@inheritDoc} */
+ @Override public Collection<Inbox<?>> inboxes(@Nullable UUID qryId, long fragmentId, long exchangeId) {
+ return remotes.values().stream()
+ .filter(makeFilter(qryId, fragmentId, exchangeId))
+ .collect(Collectors.toList());
+ }
+
+ /** {@inheritDoc} */
+ @Override public Collection<Outbox<?>> outboxes(@Nullable UUID qryId, long fragmentId, long exchangeId) {
+ return locals.values().stream()
+ .filter(makeFilter(qryId, fragmentId, exchangeId))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * @param evtMgr Event manager.
+ */
+ public void eventManager(GridEventStorageManager evtMgr) {
+ this.evtMgr = evtMgr;
+ }
+
+ /**
+ * @return Event manager.
+ */
+ public GridEventStorageManager eventManager() {
+ return evtMgr;
+ }
+
+ /** */
+ private void onNodeLeft(UUID nodeId) {
+ locals.values().forEach(n -> n.onNodeLeft(nodeId));
+ remotes.values().forEach(n -> n.onNodeLeft(nodeId));
+ }
+
+ /** */
+ private static Predicate<Mailbox<?>> makeFilter(@Nullable UUID qryId, long fragmentId, long exchangeId) {
+ Predicate<Mailbox<?>> filter = ALWAYS_TRUE;
+ if (qryId != null)
+ filter = filter.and(mailbox -> Objects.equals(mailbox.queryId(), qryId));
+ if (fragmentId != -1)
+ filter = filter.and(mailbox -> mailbox.fragmentId() == fragmentId);
+ if (exchangeId != -1)
+ filter = filter.and(mailbox -> mailbox.exchangeId() == exchangeId);
+
+ return filter;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(MailboxRegistryImpl.class, this);
+ }
+
+ /** */
+ private static class MailboxKey {
+ /** */
+ private final UUID qryId;
+
+ /** */
+ private final long exchangeId;
+
+ /** */
+ private MailboxKey(UUID qryId, long exchangeId) {
+ this.qryId = qryId;
+ this.exchangeId = exchangeId;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ MailboxKey that = (MailboxKey)o;
+
+ if (exchangeId != that.exchangeId)
+ return false;
+ return qryId.equals(that.qryId);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ int res = qryId.hashCode();
+ res = 31 * res + (int)(exchangeId ^ (exchangeId >>> 32));
+ return res;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(MailboxKey.class, this);
+ }
+ }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/QueryTaskExecutor.java
similarity index 55%
copy from modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java
copy to modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/QueryTaskExecutor.java
index 38f3f67a..6891cde 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/QueryTaskExecutor.java
@@ -15,30 +15,21 @@
* limitations under the License.
*/
-package org.apache.ignite.internal.processors.query.stat;
+package org.apache.ignite.internal.processors.query.calcite.exec;
-import org.jetbrains.annotations.Nullable;
+import java.util.UUID;
+import org.apache.ignite.internal.processors.query.calcite.util.Service;
/**
- * Types of statistics width.
+ *
*/
-public enum StatisticsType {
- /** Statistics by some particular partition. */
- PARTITION,
-
- /** Statistics by some data node. */
- LOCAL;
-
- /** Enumerated values. */
- private static final StatisticsType[] VALUES = values();
-
+public interface QueryTaskExecutor extends Service {
/**
- * Efficiently gets enumerated value from its ordinal.
+ * Executes a query task in a thread, responsible for particular query fragment.
*
- * @param ord Ordinal value.
- * @return Enumerated value or {@code null} if ordinal out of range.
+ * @param qryId Query ID.
+ * @param fragmentId Fragment ID.
+ * @param qryTask Query task.
*/
- @Nullable public static StatisticsType fromOrdinal(int ord) {
- return ord >= 0 && ord < VALUES.length ? VALUES[ord] : null;
- }
+ void execute(UUID qryId, long fragmentId, Runnable qryTask);
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/QueryTaskExecutorImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/QueryTaskExecutorImpl.java
new file mode 100644
index 0000000..c572901
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/QueryTaskExecutorImpl.java
@@ -0,0 +1,113 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.Objects;
+import java.util.UUID;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.query.calcite.CalciteQueryProcessor;
+import org.apache.ignite.internal.processors.query.calcite.util.AbstractService;
+import org.apache.ignite.internal.processors.query.calcite.util.Commons;
+import org.apache.ignite.internal.util.StripedExecutor;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.thread.IgniteStripedThreadPoolExecutor;
+
+/**
+ * TODO use {@link StripedExecutor}, registered in core pols.
+ */
+public class QueryTaskExecutorImpl extends AbstractService implements QueryTaskExecutor, Thread.UncaughtExceptionHandler {
+ /** */
+ private IgniteStripedThreadPoolExecutor stripedThreadPoolExecutor;
+
+ /** */
+ private Thread.UncaughtExceptionHandler eHnd;
+
+ /** */
+ public QueryTaskExecutorImpl(GridKernalContext ctx) {
+ super(ctx);
+ }
+
+ /**
+ * @param stripedThreadPoolExecutor Executor.
+ */
+ public void stripedThreadPoolExecutor(IgniteStripedThreadPoolExecutor stripedThreadPoolExecutor) {
+ this.stripedThreadPoolExecutor = stripedThreadPoolExecutor;
+ }
+
+ /**
+ * @param eHnd Uncaught exception handler.
+ */
+ public void exceptionHandler(Thread.UncaughtExceptionHandler eHnd) {
+ this.eHnd = eHnd;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void execute(UUID qryId, long fragmentId, Runnable qryTask) {
+ stripedThreadPoolExecutor.execute(
+ () -> {
+ try {
+ qryTask.run();
+ }
+ catch (Throwable e) {
+ U.warn(log, "Uncaught exception", e);
+
+ /*
+ * No exceptions are rethrown here to preserve the current thread from being destroyed,
+ * because other queries may be pinned to the current thread id.
+ * However, unrecoverable errors must be processed by FailureHandler.
+ */
+ uncaughtException(Thread.currentThread(), e);
+ }
+ },
+ hash(qryId, fragmentId)
+ );
+ }
+
+ /** {@inheritDoc} */
+ @Override public void onStart(GridKernalContext ctx) {
+ exceptionHandler(ctx.uncaughtExceptionHandler());
+
+ CalciteQueryProcessor proc = Objects.requireNonNull(Commons.lookupComponent(ctx, CalciteQueryProcessor.class));
+
+ stripedThreadPoolExecutor(new IgniteStripedThreadPoolExecutor(
+ ctx.config().getQueryThreadPoolSize(),
+ ctx.igniteInstanceName(),
+ "calciteQry",
+ this,
+ false,
+ 0
+ ));
+ }
+
+ /** {@inheritDoc} */
+ @Override public void tearDown() {
+ U.shutdownNow(getClass(), stripedThreadPoolExecutor, log);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void uncaughtException(Thread t, Throwable e) {
+ if (eHnd != null)
+ eHnd.uncaughtException(t, e);
+ }
+
+ /** */
+ private static int hash(UUID qryId, long fragmentId) {
+ // inlined Objects.hash(...)
+ return U.safeAbs(31 * (31 + (qryId != null ? qryId.hashCode() : 0)) + Long.hashCode(fragmentId));
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RowHandler.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RowHandler.java
new file mode 100644
index 0000000..ad03cb6
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RowHandler.java
@@ -0,0 +1,75 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.lang.reflect.Type;
+import java.util.List;
+
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
+
+/**
+ * Universal accessor and mutator for rows. It also has factory methods.
+ */
+public interface RowHandler<Row> {
+ /** */
+ Object get(int field, Row row);
+
+ /** */
+ void set(int field, Row row, Object val);
+
+ /** */
+ Row concat(Row left, Row right);
+
+ /** */
+ int columnCount(Row row);
+
+ /** */
+ default RowFactory<Row> factory(IgniteTypeFactory typeFactory, RelDataType rowType) {
+ if (rowType.isStruct())
+ return factory(typeFactory, RelOptUtil.getFieldTypeList(rowType));
+
+ return factory(typeFactory.getJavaClass(rowType));
+ }
+
+ /** */
+ default RowFactory<Row> factory(IgniteTypeFactory typeFactory, List<RelDataType> fieldTypes) {
+ Type[] types = new Type[fieldTypes.size()];
+ for (int i = 0; i < fieldTypes.size(); i++)
+ types[i] = typeFactory.getJavaClass(fieldTypes.get(i));
+
+ return factory(types);
+ }
+
+ /** */
+ RowFactory<Row> factory(Type... types);
+
+ /** */
+ @SuppressWarnings("PublicInnerClass")
+ interface RowFactory<Row> {
+ /** */
+ RowHandler<Row> handler();
+
+ /** */
+ Row create();
+
+ /** */
+ Row create(Object... fields);
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeHashIndex.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeHashIndex.java
new file mode 100644
index 0000000..8329486
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeHashIndex.java
@@ -0,0 +1,150 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.ignite.internal.processors.query.calcite.exec.exp.agg.GroupKey;
+import org.apache.ignite.internal.util.lang.GridFilteredIterator;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.X;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Runtime hash index based on on-heap hash map.
+ */
+public class RuntimeHashIndex<Row> implements RuntimeIndex<Row> {
+ /**
+ * Placeholder for keys containing NULL values. Used to skip rows with such keys, since condition NULL=NULL
+ * should not satisfy the filter.
+ */
+ private static final GroupKey NULL_KEY = new GroupKey(X.EMPTY_OBJECT_ARRAY);
+
+ /** */
+ protected final ExecutionContext<Row> ectx;
+
+ /** */
+ private final ImmutableBitSet keys;
+
+ /** Rows. */
+ private HashMap<GroupKey, List<Row>> rows;
+
+ /**
+ *
+ */
+ public RuntimeHashIndex(
+ ExecutionContext<Row> ectx,
+ ImmutableBitSet keys
+ ) {
+ this.ectx = ectx;
+
+ assert !F.isEmpty(keys);
+
+ this.keys = keys;
+ rows = new HashMap<>();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void push(Row r) {
+ GroupKey key = key(r);
+
+ if (key == NULL_KEY)
+ return;
+
+ List<Row> eqRows = rows.computeIfAbsent(key, k -> new ArrayList<>());
+
+ eqRows.add(r);
+ }
+
+ /** */
+ @Override public void close() {
+ rows.clear();
+ }
+
+ /** */
+ public Iterable<Row> scan(Supplier<Row> searchRow, @Nullable Predicate<Row> filter) {
+ return new IndexScan(searchRow, filter);
+ }
+
+ /** */
+ private GroupKey key(Row r) {
+ GroupKey.Builder b = GroupKey.builder(keys.cardinality());
+
+ for (Integer field : keys) {
+ Object fieldVal = ectx.rowHandler().get(field, r);
+
+ if (fieldVal == null)
+ return NULL_KEY;
+
+ b.add(fieldVal);
+ }
+
+ return b.build();
+ }
+
+ /**
+ *
+ */
+ private class IndexScan implements Iterable<Row>, AutoCloseable {
+ /** Search row. */
+ private final Supplier<Row> searchRow;
+
+ /** Row filter. */
+ private final Predicate<Row> filter;
+
+ /**
+ * @param searchRow Search row.
+ * @param filter Scan condition.
+ */
+ IndexScan(Supplier<Row> searchRow, @Nullable Predicate<Row> filter) {
+ this.searchRow = searchRow;
+ this.filter = filter;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close() {
+ // No-op.
+ }
+
+ /** {@inheritDoc} */
+ @NotNull @Override public Iterator<Row> iterator() {
+ GroupKey key = key(searchRow.get());
+
+ if (key == NULL_KEY)
+ return Collections.emptyIterator();
+
+ List<Row> eqRows = rows.get(key);
+
+ if (eqRows == null)
+ return Collections.emptyIterator();
+
+ return filter == null ? eqRows.iterator() : new GridFilteredIterator<Row>(eqRows.iterator()) {
+ @Override protected boolean accept(Row row) {
+ return filter.test(row);
+ }
+ };
+ }
+ }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeIndex.java
similarity index 54%
copy from modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java
copy to modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeIndex.java
index 38f3f67a..01d257c 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeIndex.java
@@ -14,31 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package org.apache.ignite.internal.processors.query.stat;
-
-import org.jetbrains.annotations.Nullable;
+package org.apache.ignite.internal.processors.query.calcite.exec;
/**
- * Types of statistics width.
+ * Runtime index interface.
+ * The temporary index is built and available only on query execution. Not stored at the schema.
*/
-public enum StatisticsType {
- /** Statistics by some particular partition. */
- PARTITION,
-
- /** Statistics by some data node. */
- LOCAL;
-
- /** Enumerated values. */
- private static final StatisticsType[] VALUES = values();
-
+public interface RuntimeIndex<Row> extends AutoCloseable {
/**
- * Efficiently gets enumerated value from its ordinal.
- *
- * @param ord Ordinal value.
- * @return Enumerated value or {@code null} if ordinal out of range.
+ * Add row to index.
*/
- @Nullable public static StatisticsType fromOrdinal(int ord) {
- return ord >= 0 && ord < VALUES.length ? VALUES[ord] : null;
- }
+ void push(Row r);
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeSortedIndex.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeSortedIndex.java
new file mode 100644
index 0000000..88df20a
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/RuntimeSortedIndex.java
@@ -0,0 +1,210 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.ignite.internal.cache.query.index.sorted.inline.IndexQueryContext;
+import org.apache.ignite.internal.util.lang.GridCursor;
+import org.apache.ignite.internal.util.typedef.F;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Runtime sorted index.
+ */
+public class RuntimeSortedIndex<Row> implements RuntimeIndex<Row>, TreeIndex<Row> {
+ /** */
+ protected final ExecutionContext<Row> ectx;
+
+ /** */
+ protected final Comparator<Row> comp;
+
+ /** Collation. */
+ private final RelCollation collation;
+
+ /** Rows. */
+ private final ArrayList<Row> rows = new ArrayList<>();
+
+ /**
+ *
+ */
+ public RuntimeSortedIndex(
+ ExecutionContext<Row> ectx,
+ RelCollation collation,
+ Comparator<Row> comp
+ ) {
+ this.ectx = ectx;
+ this.comp = comp;
+
+ assert Objects.nonNull(collation);
+
+ this.collation = collation;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void push(Row r) {
+ assert rows.isEmpty() || comp.compare(r, rows.get(rows.size() - 1)) >= 0 : "Not sorted input";
+
+ rows.add(r);
+ }
+
+ /** {@inheritDoc} */
+ @Override public void close() {
+ rows.clear();
+ }
+
+ /** {@inheritDoc} */
+ @Override public GridCursor<Row> find(Row lower, Row upper, IndexQueryContext qctx) {
+ assert qctx == null;
+
+ int firstCol = F.first(collation.getKeys());
+
+ Object lowerBound = (lower == null) ? null : ectx.rowHandler().get(firstCol, lower);
+ Object upperBound = (upper == null) ? null : ectx.rowHandler().get(firstCol, upper);
+
+ Row lowerRow = (lowerBound == null) ? null : lower;
+ Row upperRow = (upperBound == null) ? null : upper;
+
+ return new Cursor(rows, lowerRow, upperRow);
+ }
+
+ /**
+ * Creates iterable on the index.
+ */
+ public Iterable<Row> scan(
+ ExecutionContext<Row> ectx,
+ RelDataType rowType,
+ Predicate<Row> filter,
+ Supplier<Row> lowerBound,
+ Supplier<Row> upperBound
+ ) {
+ return new IndexScan(rowType, this, filter, lowerBound, upperBound);
+ }
+
+ /**
+ * Cursor to navigate through a sorted list with duplicates.
+ */
+ private class Cursor implements GridCursor<Row> {
+ /** List of rows. */
+ private final List<Row> rows;
+
+ /** Upper bound. */
+ private final Row upper;
+
+ /** Current row. */
+ private Row row;
+
+ /** Current index of list element. */
+ private int idx;
+
+ /**
+ * @param rows List of rows.
+ * @param lower Lower bound (inclusive).
+ * @param upper Upper bound (inclusive).
+ */
+ Cursor(List<Row> rows, @Nullable Row lower, @Nullable Row upper) {
+ this.rows = rows;
+ this.upper = upper;
+
+ idx = lower == null ? 0 : lowerBound(rows, lower);
+ }
+
+ /**
+ * Searches the lower bound (skipping duplicates) using a binary search.
+ *
+ * @param rows List of rows.
+ * @param bound Lower bound.
+ * @return Lower bound position in the list.
+ */
+ private int lowerBound(List<Row> rows, Row bound) {
+ int low = 0, high = rows.size() - 1, idx = -1;
+
+ while (low <= high) {
+ int mid = (high - low) / 2 + low;
+ int compRes = comp.compare(rows.get(mid), bound);
+
+ if (compRes > 0)
+ high = mid - 1;
+ else if (compRes == 0) {
+ idx = mid;
+ high = mid - 1;
+ }
+ else
+ low = mid + 1;
+ }
+
+ return idx == -1 ? low : idx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean next() {
+ if (idx == rows.size() || (upper != null && comp.compare(upper, rows.get(idx)) < 0))
+ return false;
+
+ row = rows.get(idx++);
+
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Row get() {
+ return row;
+ }
+ }
+
+ /**
+ *
+ */
+ private class IndexScan extends AbstractIndexScan<Row, Row> {
+ /**
+ * @param rowType Row type.
+ * @param idx Physical index.
+ * @param filter Additional filters.
+ * @param lowerBound Lower index scan bound.
+ * @param upperBound Upper index scan bound.
+ */
+ IndexScan(
+ RelDataType rowType,
+ TreeIndex<Row> idx,
+ Predicate<Row> filter,
+ Supplier<Row> lowerBound,
+ Supplier<Row> upperBound) {
+ super(RuntimeSortedIndex.this.ectx, rowType, idx, filter, lowerBound, upperBound, null);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected Row row2indexRow(Row bound) {
+ return bound;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected Row indexRow2Row(Row row) {
+ return row;
+ }
+
+ /** */
+ @Override protected IndexQueryContext indexQueryContext() {
+ return null;
+ }
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/SystemViewScan.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/SystemViewScan.java
new file mode 100644
index 0000000..89392be
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/SystemViewScan.java
@@ -0,0 +1,148 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.ignite.internal.processors.query.calcite.exec.RowHandler.RowFactory;
+import org.apache.ignite.internal.processors.query.calcite.schema.SystemViewColumnDescriptor;
+import org.apache.ignite.internal.processors.query.calcite.schema.SystemViewTableDescriptorImpl;
+import org.apache.ignite.internal.processors.query.calcite.util.TypeUtils;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.lang.IgniteClosure;
+import org.apache.ignite.lang.IgnitePredicate;
+import org.apache.ignite.spi.systemview.view.FiltrableSystemView;
+import org.apache.ignite.spi.systemview.view.SystemView;
+import org.jetbrains.annotations.Nullable;
+
+/** */
+public class SystemViewScan<Row, ViewRow> implements Iterable<Row> {
+ /** */
+ private final ExecutionContext<Row> ectx;
+
+ /** */
+ private final SystemViewTableDescriptorImpl<ViewRow> desc;
+
+ /** */
+ private final RowFactory<Row> factory;
+
+ /** */
+ private final Supplier<Row> searchRow;
+
+ /** */
+ private final Predicate<Row> filters;
+
+ /** */
+ private final Function<Row, Row> rowTransformer;
+
+ /** Participating colunms. */
+ private final ImmutableBitSet requiredColumns;
+
+ /** System view field names (for filtering). */
+ private final String[] filterableFieldNames;
+
+ /** System view field types (for filtering). */
+ private final Class<?>[] filterableFieldTypes;
+
+ /** */
+ public SystemViewScan(
+ ExecutionContext<Row> ectx,
+ SystemViewTableDescriptorImpl<ViewRow> desc,
+ @Nullable Supplier<Row> searchRow,
+ Predicate<Row> filters,
+ Function<Row, Row> rowTransformer,
+ @Nullable ImmutableBitSet requiredColumns
+ ) {
+ this.ectx = ectx;
+ this.desc = desc;
+ this.searchRow = searchRow;
+ this.filters = filters;
+ this.rowTransformer = rowTransformer;
+ this.requiredColumns = requiredColumns;
+
+ RelDataType rowType = desc.rowType(ectx.getTypeFactory(), requiredColumns);
+
+ factory = ectx.rowHandler().factory(ectx.getTypeFactory(), rowType);
+
+ filterableFieldNames = new String[desc.columnDescriptors().size()];
+ filterableFieldTypes = new Class<?>[desc.columnDescriptors().size()];
+
+ if (desc.isFiltrable()) {
+ for (SystemViewColumnDescriptor col : desc.columnDescriptors()) {
+ if (col.isFiltrable()) {
+ filterableFieldNames[col.fieldIndex()] = col.originalName();
+ filterableFieldTypes[col.fieldIndex()] = col.storageType();
+ }
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public Iterator<Row> iterator() {
+ SystemView<ViewRow> view = desc.systemView();
+
+ Iterator<ViewRow> viewIter;
+
+ if (searchRow != null) {
+ assert view instanceof FiltrableSystemView : view;
+
+ Row searchValues = searchRow.get();
+
+ RowHandler<Row> rowHnd = ectx.rowHandler();
+ Map<String, Object> filterMap = null;
+
+ for (int i = 0; i < filterableFieldNames.length; i++) {
+ if (filterableFieldNames[i] == null)
+ continue;
+
+ Object val = rowHnd.get(i, searchValues);
+
+ if (val != ectx.unspecifiedValue()) {
+ if (filterMap == null)
+ filterMap = new HashMap<>();
+
+ filterMap.put(filterableFieldNames[i], TypeUtils.fromInternal(ectx, val, filterableFieldTypes[i]));
+ }
+ }
+
+ viewIter = F.isEmpty(filterMap) ? view.iterator() : ((FiltrableSystemView<ViewRow>)view).iterator(filterMap);
+ }
+ else
+ viewIter = view.iterator();
+
+ Iterator<Row> iter = F.iterator(
+ viewIter,
+ row -> desc.toRow(ectx, row, factory, requiredColumns),
+ true);
+
+ if (rowTransformer != null || filters != null) {
+ IgniteClosure<Row, Row> trans = rowTransformer == null ? F.identity() : rowTransformer::apply;
+ IgnitePredicate<Row> filter = filters == null ? F.alwaysTrue() : filters::test;
+
+ iter = F.iterator(iter, trans, true, filter);
+ }
+
+ return iter;
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/TableFunctionScan.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/TableFunctionScan.java
new file mode 100644
index 0000000..a853184
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/TableFunctionScan.java
@@ -0,0 +1,46 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.Iterator;
+import java.util.function.Supplier;
+import org.apache.ignite.internal.processors.query.calcite.exec.RowHandler.RowFactory;
+import org.apache.ignite.internal.util.typedef.F;
+
+/** */
+public class TableFunctionScan<Row> implements Iterable<Row> {
+ /** */
+ private final Supplier<Iterable<Object[]>> dataSupplier;
+
+ /** */
+ private final RowFactory<Row> rowFactory;
+
+ /** */
+ public TableFunctionScan(
+ Supplier<Iterable<Object[]>> dataSupplier,
+ RowFactory<Row> rowFactory
+ ) {
+ this.dataSupplier = dataSupplier;
+ this.rowFactory = rowFactory;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Iterator<Row> iterator() {
+ return F.iterator(dataSupplier.get(), rowFactory::create, true);
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/TableScan.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/TableScan.java
new file mode 100644
index 0000000..2953053
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/TableScan.java
@@ -0,0 +1,282 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.cluster.ClusterTopologyException;
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTopologyFuture;
+import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition;
+import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
+import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology;
+import org.apache.ignite.internal.processors.cache.mvcc.MvccSnapshot;
+import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
+import org.apache.ignite.internal.processors.query.calcite.exec.RowHandler.RowFactory;
+import org.apache.ignite.internal.processors.query.calcite.schema.CacheTableDescriptor;
+import org.apache.ignite.internal.util.lang.GridCursor;
+import org.apache.ignite.internal.util.lang.GridIteratorAdapter;
+import org.apache.ignite.internal.util.typedef.F;
+import org.jetbrains.annotations.Nullable;
+
+/** */
+public class TableScan<Row> implements Iterable<Row>, AutoCloseable {
+ /** */
+ private final GridCacheContext<?, ?> cctx;
+
+ /** */
+ private final Predicate<Row> filters;
+
+ /** */
+ private final ExecutionContext<Row> ectx;
+
+ /** */
+ private final CacheTableDescriptor desc;
+
+ /** */
+ private final RowFactory<Row> factory;
+
+ /** */
+ private final AffinityTopologyVersion topVer;
+
+ /** */
+ private final int[] parts;
+
+ /** */
+ private final MvccSnapshot mvccSnapshot;
+
+ /** */
+ private volatile List<GridDhtLocalPartition> reserved;
+
+ /** */
+ private final Function<Row, Row> rowTransformer;
+
+ /** Participating colunms. */
+ private final ImmutableBitSet requiredColunms;
+
+ /** */
+ public TableScan(
+ ExecutionContext<Row> ectx,
+ CacheTableDescriptor desc,
+ int[] parts,
+ Predicate<Row> filters,
+ Function<Row, Row> rowTransformer,
+ @Nullable ImmutableBitSet requiredColunms
+ ) {
+ this.ectx = ectx;
+ cctx = desc.cacheContext();
+ this.desc = desc;
+ this.parts = parts;
+ this.filters = filters;
+ this.rowTransformer = rowTransformer;
+ this.requiredColunms = requiredColunms;
+
+ RelDataType rowType = desc.rowType(this.ectx.getTypeFactory(), requiredColunms);
+
+ factory = this.ectx.rowHandler().factory(this.ectx.getTypeFactory(), rowType);
+ topVer = ectx.topologyVersion();
+ mvccSnapshot = ectx.mvccSnapshot();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Iterator<Row> iterator() {
+ reserve();
+ try {
+ return new IteratorImpl();
+ }
+ catch (Exception e) {
+ release();
+
+ throw e;
+ }
+ }
+
+ /** */
+ @Override public void close() {
+ release();
+ }
+
+ /** */
+ private synchronized void reserve() {
+ if (reserved != null)
+ return;
+
+ GridDhtPartitionTopology top = cctx.topology();
+ top.readLock();
+
+ GridDhtTopologyFuture topFut = top.topologyVersionFuture();
+
+ boolean done = topFut.isDone();
+
+ if (!done || !(topFut.topologyVersion().compareTo(topVer) >= 0
+ && cctx.shared().exchange().lastAffinityChangedTopologyVersion(topFut.initialVersion()).compareTo(topVer) <= 0)) {
+ top.readUnlock();
+
+ throw new ClusterTopologyException("Topology was changed. Please retry on stable topology.");
+ }
+
+ List<GridDhtLocalPartition> toReserve;
+ if (cctx.isReplicated()) {
+ int partsCnt = cctx.affinity().partitions();
+ toReserve = new ArrayList<>(partsCnt);
+ for (int i = 0; i < partsCnt; i++)
+ toReserve.add(top.localPartition(i));
+ }
+ else if (cctx.isPartitioned()) {
+ assert parts != null;
+
+ toReserve = new ArrayList<>(parts.length);
+ for (int i = 0; i < parts.length; i++)
+ toReserve.add(top.localPartition(parts[i]));
+ }
+ else {
+ assert cctx.isLocal();
+
+ toReserve = Collections.emptyList();
+ }
+
+ reserved = new ArrayList<>(toReserve.size());
+
+ try {
+ for (GridDhtLocalPartition part : toReserve) {
+ if (part == null || !part.reserve())
+ throw new ClusterTopologyException("Failed to reserve partition for query execution. Retry on stable topology.");
+ else if (part.state() != GridDhtPartitionState.OWNING) {
+ part.release();
+
+ throw new ClusterTopologyException("Failed to reserve partition for query execution. Retry on stable topology.");
+ }
+
+ reserved.add(part);
+ }
+ }
+ catch (Exception e) {
+ release();
+
+ throw e;
+ }
+ finally {
+ top.readUnlock();
+ }
+ }
+
+ /** */
+ private synchronized void release() {
+ if (F.isEmpty(reserved))
+ return;
+
+ reserved.forEach(GridDhtLocalPartition::release);
+
+ reserved = null;
+ }
+
+ /**
+ * Table scan iterator.
+ */
+ private class IteratorImpl extends GridIteratorAdapter<Row> {
+ /** */
+ private final Queue<GridDhtLocalPartition> parts;
+
+ /** */
+ private GridCursor<? extends CacheDataRow> cur;
+
+ /** */
+ private Row next;
+
+ /** */
+ private IteratorImpl() {
+ assert reserved != null;
+
+ parts = new ArrayDeque<>(reserved);
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean hasNextX() throws IgniteCheckedException {
+ advance();
+
+ return next != null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public Row nextX() throws IgniteCheckedException {
+ advance();
+
+ if (next == null)
+ throw new NoSuchElementException();
+
+ Row next = this.next;
+
+ this.next = null;
+
+ return next;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void removeX() {
+ throw new UnsupportedOperationException("Remove is not supported.");
+ }
+
+ /** */
+ private void advance() throws IgniteCheckedException {
+ assert parts != null;
+
+ if (next != null)
+ return;
+
+ while (true) {
+ if (cur == null) {
+ GridDhtLocalPartition part = parts.poll();
+ if (part == null)
+ break;
+
+ cur = part.dataStore().cursor(cctx.cacheId(), mvccSnapshot);
+ }
+
+ if (cur.next()) {
+ CacheDataRow row = cur.get();
+
+ if (!desc.match(row))
+ continue;
+
+ Row r = desc.toRow(ectx, row, factory, requiredColunms);
+
+ if (filters != null && !filters.test(r))
+ continue;
+
+ if (rowTransformer != null)
+ r = rowTransformer.apply(r);
+
+ next = r;
+ break;
+ } else
+ cur = null;
+ }
+ }
+ }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/TreeIndex.java
similarity index 55%
copy from modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java
copy to modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/TreeIndex.java
index 38f3f67a..91cb912 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/stat/StatisticsType.java
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/TreeIndex.java
@@ -14,31 +14,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.ignite.internal.processors.query.calcite.exec;
-package org.apache.ignite.internal.processors.query.stat;
-
-import org.jetbrains.annotations.Nullable;
+import org.apache.ignite.internal.cache.query.index.sorted.inline.IndexQueryContext;
+import org.apache.ignite.internal.util.lang.GridCursor;
/**
- * Types of statistics width.
+ * Tree index interface.
+ *
+ * @param <R> Indexing row type.
*/
-public enum StatisticsType {
- /** Statistics by some particular partition. */
- PARTITION,
-
- /** Statistics by some data node. */
- LOCAL;
-
- /** Enumerated values. */
- private static final StatisticsType[] VALUES = values();
-
+public interface TreeIndex<R> {
/**
- * Efficiently gets enumerated value from its ordinal.
+ * Index lookup method.
*
- * @param ord Ordinal value.
- * @return Enumerated value or {@code null} if ordinal out of range.
+ * @param lower Lower bound.
+ * @param upper Upper bound.
+ * @param qctx Index query context.
+ * @return Cursor over the rows within bounds.
*/
- @Nullable public static StatisticsType fromOrdinal(int ord) {
- return ord >= 0 && ord < VALUES.length ? VALUES[ord] : null;
- }
+ public GridCursor<R> find(R lower, R upper, IndexQueryContext qctx);
}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/DdlCommandHandler.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/DdlCommandHandler.java
new file mode 100644
index 0000000..1789eb1
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/DdlCommandHandler.java
@@ -0,0 +1,403 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec.ddl;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.function.Supplier;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.Table;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
+import org.apache.ignite.internal.processors.cache.GridCacheProcessor;
+import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
+import org.apache.ignite.internal.processors.query.GridQueryProcessor;
+import org.apache.ignite.internal.processors.query.GridQuerySchemaManager;
+import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.processors.query.QueryEntityEx;
+import org.apache.ignite.internal.processors.query.QueryField;
+import org.apache.ignite.internal.processors.query.QueryUtils;
+import org.apache.ignite.internal.processors.query.calcite.prepare.ddl.AlterTableAddCommand;
+import org.apache.ignite.internal.processors.query.calcite.prepare.ddl.AlterTableDropCommand;
+import org.apache.ignite.internal.processors.query.calcite.prepare.ddl.ColumnDefinition;
+import org.apache.ignite.internal.processors.query.calcite.prepare.ddl.CreateTableCommand;
+import org.apache.ignite.internal.processors.query.calcite.prepare.ddl.DdlCommand;
+import org.apache.ignite.internal.processors.query.calcite.prepare.ddl.DropTableCommand;
+import org.apache.ignite.internal.processors.query.calcite.prepare.ddl.NativeCommandWrapper;
+import org.apache.ignite.internal.processors.query.calcite.prepare.ddl.TransactionCommand;
+import org.apache.ignite.internal.processors.query.calcite.schema.IgniteCacheTable;
+import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory;
+import org.apache.ignite.internal.processors.query.calcite.util.Commons;
+import org.apache.ignite.internal.processors.query.schema.SchemaOperationException;
+import org.apache.ignite.internal.processors.security.IgniteSecurity;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.plugin.security.SecurityPermission;
+
+import static org.apache.ignite.internal.processors.query.QueryUtils.convert;
+import static org.apache.ignite.internal.processors.query.QueryUtils.isDdlOnSchemaSupported;
+
+/** */
+public class DdlCommandHandler {
+ /** */
+ private final Supplier<GridQueryProcessor> qryProcessorSupp;
+
+ /** */
+ private final GridCacheProcessor cacheProcessor;
+
+ /** */
+ private final IgniteSecurity security;
+
+ /** */
+ private final Supplier<SchemaPlus> schemaSupp;
+
+ /** */
+ private final NativeCommandHandler nativeCmdHnd;
+
+ /** */
+ private final GridQuerySchemaManager schemaMgr;
+
+ /** */
+ public DdlCommandHandler(Supplier<GridQueryProcessor> qryProcessorSupp, GridCacheProcessor cacheProcessor,
+ IgniteSecurity security, Supplier<SchemaPlus> schemaSupp) {
+ this.qryProcessorSupp = qryProcessorSupp;
+ this.cacheProcessor = cacheProcessor;
+ this.security = security;
+ this.schemaSupp = schemaSupp;
+ schemaMgr = new SchemaManager(schemaSupp);
+ nativeCmdHnd = new NativeCommandHandler(cacheProcessor.context().kernalContext(), schemaMgr);
+ }
+
+ /** */
+ public void handle(UUID qryId, DdlCommand cmd) throws IgniteCheckedException {
+ try {
+ if (cmd instanceof TransactionCommand)
+ return;
+
+ if (cmd instanceof CreateTableCommand)
+ handle0((CreateTableCommand)cmd);
+ else if (cmd instanceof DropTableCommand)
+ handle0((DropTableCommand)cmd);
+ else if (cmd instanceof AlterTableAddCommand)
+ handle0((AlterTableAddCommand)cmd);
+ else if (cmd instanceof AlterTableDropCommand)
+ handle0((AlterTableDropCommand)cmd);
+ else if (cmd instanceof NativeCommandWrapper)
+ nativeCmdHnd.handle(qryId, (NativeCommandWrapper)cmd);
+ else {
+ throw new IgniteSQLException("Unsupported DDL operation [" +
+ "cmdName=" + (cmd == null ? null : cmd.getClass().getSimpleName()) + "; " +
+ "cmd=\"" + cmd + "\"]", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
+ }
+ }
+ catch (SchemaOperationException e) {
+ throw convert(e);
+ }
+ }
+
+ /** */
+ private void handle0(CreateTableCommand cmd) throws IgniteCheckedException {
+ security.authorize(cmd.cacheName(), SecurityPermission.CACHE_CREATE);
+
+ isDdlOnSchemaSupported(cmd.schemaName());
+
+ if (schemaSupp.get().getSubSchema(cmd.schemaName()).getTable(cmd.tableName()) != null) {
+ if (cmd.ifNotExists())
+ return;
+
+ throw new SchemaOperationException(SchemaOperationException.CODE_TABLE_EXISTS, cmd.tableName());
+ }
+
+ CacheConfiguration<?, ?> ccfg = new CacheConfiguration<>(cmd.tableName());
+
+ QueryEntity e = toQueryEntity(cmd);
+
+ ccfg.setQueryEntities(Collections.singleton(e));
+ ccfg.setSqlSchema(cmd.schemaName());
+
+ SchemaOperationException err =
+ QueryUtils.checkQueryEntityConflicts(ccfg, cacheProcessor.cacheDescriptors().values());
+
+ if (err != null)
+ throw convert(err);
+
+ if (!F.isEmpty(cmd.cacheName()) && cacheProcessor.cacheDescriptor(cmd.cacheName()) != null) {
+ qryProcessorSupp.get().dynamicAddQueryEntity(
+ cmd.cacheName(),
+ cmd.schemaName(),
+ e,
+ null,
+ true
+ ).get();
+ }
+ else {
+ qryProcessorSupp.get().dynamicTableCreate(
+ cmd.schemaName(),
+ e,
+ cmd.templateName(),
+ cmd.cacheName(),
+ cmd.cacheGroup(),
+ cmd.dataRegionName(),
+ cmd.affinityKey(),
+ cmd.atomicityMode(),
+ cmd.writeSynchronizationMode(),
+ cmd.backups(),
+ cmd.ifNotExists(),
+ cmd.encrypted(),
+ null
+ );
+ }
+ }
+
+ /** */
+ private void handle0(DropTableCommand cmd) throws IgniteCheckedException {
+ isDdlOnSchemaSupported(cmd.schemaName());
+
+ Table tbl = schemaSupp.get().getSubSchema(cmd.schemaName()).getTable(cmd.tableName());
+
+ if (tbl == null) {
+ if (!cmd.ifExists())
+ throw new SchemaOperationException(SchemaOperationException.CODE_TABLE_NOT_FOUND, cmd.tableName());
+
+ return;
+ }
+
+ assert tbl instanceof IgniteCacheTable : tbl;
+
+ String cacheName = ((IgniteCacheTable)tbl).descriptor().cacheInfo().name();
+
+ security.authorize(cacheName, SecurityPermission.CACHE_DESTROY);
+
+ qryProcessorSupp.get().dynamicTableDrop(cacheName, cmd.tableName(), cmd.ifExists());
+ }
+
+ /** */
+ private void handle0(AlterTableAddCommand cmd) throws IgniteCheckedException {
+ isDdlOnSchemaSupported(cmd.schemaName());
+
+ GridQueryTypeDescriptor typeDesc = schemaMgr.typeDescriptorForTable(cmd.schemaName(), cmd.tableName());
+
+ if (typeDesc == null) {
+ if (!cmd.ifTableExists())
+ throw new SchemaOperationException(SchemaOperationException.CODE_TABLE_NOT_FOUND, cmd.tableName());
+ }
+ else {
+ if (QueryUtils.isSqlType(typeDesc.valueClass())) {
+ throw new SchemaOperationException("Cannot add column(s) because table was created " +
+ "with WRAP_VALUE=false option.");
+ }
+
+ List<QueryField> cols = new ArrayList<>(cmd.columns().size());
+
+ boolean allFieldsNullable = true;
+
+ for (ColumnDefinition col : cmd.columns()) {
+ if (typeDesc.fields().containsKey(col.name())) {
+ if (!cmd.ifColumnNotExists())
+ throw new SchemaOperationException(SchemaOperationException.CODE_COLUMN_EXISTS, col.name());
+ else
+ continue;
+ }
+
+ Type javaType = Commons.typeFactory().getResultClass(col.type());
+
+ String typeName = javaType instanceof Class ? ((Class<?>)javaType).getName() : javaType.getTypeName();
+
+ Integer precession = col.precision();
+ Integer scale = col.scale();
+
+ QueryField field = new QueryField(col.name(), typeName,
+ col.type().isNullable(), col.defaultValue(),
+ precession == null ? -1 : precession, scale == null ? -1 : scale);
+
+ cols.add(field);
+
+ allFieldsNullable &= field.isNullable();
+ }
+
+ if (!F.isEmpty(cols)) {
+ GridCacheContextInfo<?, ?> ctxInfo = schemaMgr.cacheInfoForTable(cmd.schemaName(), cmd.tableName());
+
+ assert ctxInfo != null;
+
+ if (!allFieldsNullable)
+ QueryUtils.checkNotNullAllowed(ctxInfo.config());
+
+ qryProcessorSupp.get().dynamicColumnAdd(ctxInfo.name(), cmd.schemaName(),
+ typeDesc.tableName(), cols, cmd.ifTableExists(), cmd.ifColumnNotExists()).get();
+ }
+ }
+ }
+
+ /** */
+ private void handle0(AlterTableDropCommand cmd) throws IgniteCheckedException {
+ isDdlOnSchemaSupported(cmd.schemaName());
+
+ GridQueryTypeDescriptor typeDesc = schemaMgr.typeDescriptorForTable(cmd.schemaName(), cmd.tableName());
+
+ if (typeDesc == null) {
+ if (!cmd.ifTableExists())
+ throw new SchemaOperationException(SchemaOperationException.CODE_TABLE_NOT_FOUND, cmd.tableName());
+ }
+ else {
+ GridCacheContextInfo<?, ?> ctxInfo = schemaMgr.cacheInfoForTable(cmd.schemaName(), cmd.tableName());
+
+ GridCacheContext<?, ?> cctx = ctxInfo.cacheContext();
+
+ assert cctx != null;
+
+ if (cctx.mvccEnabled()) {
+ throw new IgniteSQLException("Cannot drop column(s) with enabled MVCC. " +
+ "Operation is unsupported at the moment.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
+ }
+
+ if (QueryUtils.isSqlType(typeDesc.valueClass())) {
+ throw new SchemaOperationException("Cannot drop column(s) because table was created " +
+ "with WRAP_VALUE=false option.");
+ }
+
+ List<String> cols = new ArrayList<>(cmd.columns().size());
+
+ for (String colName : cmd.columns()) {
+ if (!typeDesc.fields().containsKey(colName)) {
+ if (!cmd.ifColumnExists())
+ throw new SchemaOperationException(SchemaOperationException.CODE_COLUMN_NOT_FOUND, colName);
+ else
+ continue;
+ }
+
+ SchemaOperationException err = QueryUtils.validateDropColumn(typeDesc, colName);
+
+ if (err != null)
+ throw err;
+
+ cols.add(colName);
+ }
+
+ if (!F.isEmpty(cols)) {
+ qryProcessorSupp.get().dynamicColumnRemove(ctxInfo.name(), cmd.schemaName(),
+ typeDesc.tableName(), cols, cmd.ifTableExists(), cmd.ifColumnExists()).get();
+ }
+ }
+ }
+
+ /** */
+ private QueryEntity toQueryEntity(CreateTableCommand cmd) {
+ QueryEntity res = new QueryEntity();
+
+ res.setTableName(cmd.tableName());
+
+ Set<String> notNullFields = null;
+
+ HashMap<String, Object> dfltValues = new HashMap<>();
+
+ Map<String, Integer> precision = new HashMap<>();
+ Map<String, Integer> scale = new HashMap<>();
+
+ IgniteTypeFactory tf = Commons.typeFactory();
+
+ for (ColumnDefinition col : cmd.columns()) {
+ String name = col.name();
+
+ Type javaType = tf.getResultClass(col.type());
+
+ String typeName = javaType instanceof Class ? ((Class<?>)javaType).getName() : javaType.getTypeName();
+
+ res.addQueryField(name, typeName, null);
+
+ if (!col.nullable()) {
+ if (notNullFields == null)
+ notNullFields = new HashSet<>();
+
+ notNullFields.add(name);
+ }
+
+ if (col.defaultValue() != null)
+ dfltValues.put(name, col.defaultValue());
+
+ if (col.precision() != null)
+ precision.put(name, col.precision());
+
+ if (col.scale() != null)
+ scale.put(name, col.scale());
+ }
+
+ if (!F.isEmpty(dfltValues))
+ res.setDefaultFieldValues(dfltValues);
+
+ if (!F.isEmpty(precision))
+ res.setFieldsPrecision(precision);
+
+ if (!F.isEmpty(scale))
+ res.setFieldsScale(scale);
+
+ String valTypeName = QueryUtils.createTableValueTypeName(cmd.schemaName(), cmd.tableName());
+
+ String keyTypeName;
+ if ((!F.isEmpty(cmd.primaryKeyColumns()) && cmd.primaryKeyColumns().size() > 1) || !F.isEmpty(cmd.keyTypeName())) {
+ keyTypeName = cmd.keyTypeName();
+
+ if (F.isEmpty(keyTypeName))
+ keyTypeName = QueryUtils.createTableKeyTypeName(valTypeName);
+
+ if (!F.isEmpty(cmd.primaryKeyColumns())) {
+ res.setKeyFields(new LinkedHashSet<>(cmd.primaryKeyColumns()));
+
+ res = new QueryEntityEx(res).setPreserveKeysOrder(true);
+ }
+ }
+ else if (!F.isEmpty(cmd.primaryKeyColumns()) && cmd.primaryKeyColumns().size() == 1) {
+ String pkFieldName = cmd.primaryKeyColumns().get(0);
+
+ keyTypeName = res.getFields().get(pkFieldName);
+
+ res.setKeyFieldName(pkFieldName);
+ }
+ else {
+ // if pk is not explicitly set, we create it ourselves
+ keyTypeName = IgniteUuid.class.getName();
+
+ res = new QueryEntityEx(res).implicitPk(true);
+ }
+
+ res.setValueType(F.isEmpty(cmd.valueTypeName()) ? valTypeName : cmd.valueTypeName());
+ res.setKeyType(keyTypeName);
+
+ if (!F.isEmpty(notNullFields)) {
+ QueryEntityEx res0 = new QueryEntityEx(res);
+
+ res0.setNotNullFields(notNullFields);
+
+ res = res0;
+ }
+
+ return res;
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/NativeCommandHandler.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/NativeCommandHandler.java
new file mode 100644
index 0000000..3cca9d6
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/NativeCommandHandler.java
@@ -0,0 +1,51 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec.ddl;
+
+import java.util.List;
+import java.util.UUID;
+import org.apache.ignite.cache.query.FieldsQueryCursor;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.query.GridQuerySchemaManager;
+import org.apache.ignite.internal.processors.query.calcite.prepare.ddl.NativeCommandWrapper;
+import org.apache.ignite.internal.sql.SqlCommandProcessor;
+
+/**
+ * Handler for Ignite native (core module) commands.
+ */
+public class NativeCommandHandler {
+ /** Command processor. */
+ private final SqlCommandProcessor proc;
+
+ /**
+ * @param ctx Context.
+ */
+ public NativeCommandHandler(GridKernalContext ctx, GridQuerySchemaManager schemaMgr) {
+ proc = new SqlCommandProcessor(ctx, schemaMgr);
+ }
+
+ /**
+ * @param qryId Query id.
+ * @param cmd Native command.
+ */
+ public FieldsQueryCursor<List<?>> handle(UUID qryId, NativeCommandWrapper cmd) {
+ assert proc.isCommandSupported(cmd.command()) : cmd.command();
+
+ return proc.runCommand(cmd.command());
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/SchemaManager.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/SchemaManager.java
new file mode 100644
index 0000000..9e2b243
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/ddl/SchemaManager.java
@@ -0,0 +1,85 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec.ddl;
+
+import java.util.function.Supplier;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.Table;
+import org.apache.ignite.internal.processors.cache.GridCacheContextInfo;
+import org.apache.ignite.internal.processors.query.GridQuerySchemaManager;
+import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
+import org.apache.ignite.internal.processors.query.calcite.schema.IgniteCacheTable;
+import org.apache.ignite.internal.processors.query.calcite.schema.IgniteTable;
+
+/**
+ * Schema manager.
+ */
+class SchemaManager implements GridQuerySchemaManager {
+ /** Schema holder. */
+ private final Supplier<SchemaPlus> schemaSupp;
+
+ /**
+ * @param schemaSupp Schema supplier.
+ */
+ SchemaManager(Supplier<SchemaPlus> schemaSupp) {
+ this.schemaSupp = schemaSupp;
+ }
+
+ /** {@inheritDoc} */
+ @Override public GridQueryTypeDescriptor typeDescriptorForTable(String schemaName, String tableName) {
+ SchemaPlus schema = schemaSupp.get().getSubSchema(schemaName);
+
+ if (schema == null)
+ return null;
+
+ IgniteCacheTable tbl = (IgniteCacheTable)schema.getTable(tableName);
+
+ return tbl == null ? null : tbl.descriptor().typeDescription();
+ }
+
+ /** {@inheritDoc} */
+ @Override public GridQueryTypeDescriptor typeDescriptorForIndex(String schemaName, String idxName) {
+ SchemaPlus schema = schemaSupp.get().getSubSchema(schemaName);
+
+ if (schema == null)
+ return null;
+
+ for (String tableName : schema.getTableNames()) {
+ Table tbl = schema.getTable(tableName);
+
+ if (tbl instanceof IgniteCacheTable && ((IgniteTable)tbl).getIndex(idxName) != null)
+ return ((IgniteCacheTable)tbl).descriptor().typeDescription();
+ }
+
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public <K, V> GridCacheContextInfo<K, V> cacheInfoForTable(String schemaName, String tableName) {
+ SchemaPlus schema = schemaSupp.get().getSubSchema(schemaName);
+
+ if (schema == null)
+ return null;
+
+ Table tbl = schema.getTable(tableName);
+
+ IgniteCacheTable cachetbl = tbl instanceof IgniteCacheTable ? (IgniteCacheTable)tbl : null;
+
+ return cachetbl == null ? null : (GridCacheContextInfo<K, V>)cachetbl.descriptor().cacheInfo();
+ }
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/BiScalar.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/BiScalar.java
new file mode 100644
index 0000000..f7b92cb
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/BiScalar.java
@@ -0,0 +1,27 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec.exp;
+
+import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext;
+
+/** */
+@FunctionalInterface
+public interface BiScalar extends Scalar {
+ /** Multi input and single output. */
+ void execute(ExecutionContext ctx, Object in1, Object in2, Object out);
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/CallImplementor.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/CallImplementor.java
new file mode 100644
index 0000000..6328938
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/CallImplementor.java
@@ -0,0 +1,42 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec.exp;
+
+import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.rex.RexCall;
+
+/**
+ * Implements a call via given translator.
+ *
+ * @see org.apache.calcite.schema.ScalarFunction
+ * @see org.apache.calcite.schema.TableFunction
+ * @see RexImpTable
+ */
+public interface CallImplementor {
+ /**
+ * Implements a call.
+ *
+ * @param translator Translator for the call
+ * @param call Call that should be implemented
+ * @param nullAs The desired mode of {@code null} translation
+ * @return Translated call
+ */
+ Expression implement(
+ RexToLixTranslator translator,
+ RexCall call,
+ RexImpTable.NullAs nullAs);
+}
diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/ConverterUtils.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/ConverterUtils.java
new file mode 100644
index 0000000..671fb42
--- /dev/null
+++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/exec/exp/ConverterUtils.java
@@ -0,0 +1,458 @@
+/*
+ * 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.ignite.internal.processors.query.calcite.exec.exp;
+
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.calcite.adapter.enumerable.RexImpTable;
+import org.apache.calcite.linq4j.tree.ConstantExpression;
+import org.apache.calcite.linq4j.tree.ConstantUntypedNull;
+import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.linq4j.tree.ExpressionType;
+import org.apache.calcite.linq4j.tree.Expressions;
+import org.apache.calcite.linq4j.tree.Primitive;
+import org.apache.calcite.linq4j.tree.Types;
+import org.apache.calcite.linq4j.tree.UnaryExpression;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.runtime.SqlFunctions;
+import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.Util;
+
+/** */
+public class ConverterUtils {
+ /** */
+ private ConverterUtils() {
+ }
+
+ /**
+ * In Calcite, {@code java.sql.Date} and {@code java.sql.Time} are stored as {@code Integer} type, {@code
+ * java.sql.Timestamp} is stored as {@code Long} type.
+ */
+ static Expression toInternal(Expression operand, Type targetType) {
+ return toInternal(operand, operand.getType(), targetType);
+ }
+
+ /** */
+ private static Expression toInternal(Expression operand,
+ Type fromType, Type targetType) {
+ if (fromType == java.sql.Date.class) {
+ if (targetType == int.class)
+ return Expressions.call(BuiltInMethod.DATE_TO_INT.method, operand);
+ else if (targetType == Integer.class)
+ return Expressions.call(BuiltInMethod.DATE_TO_INT_OPTIONAL.method, operand);
+ }
+ else if (fromType == java.sql.Time.class) {
+ if (targetType == int.class)
+ return Expressions.call(BuiltInMethod.TIME_TO_INT.method, operand);
+ else if (targetType == Integer.class)
+ return Expressions.call(BuiltInMethod.TIME_TO_INT_OPTIONAL.method, operand);
+ }
+ else if (fromType == java.sql.Timestamp.class) {
+ if (targetType == long.class)
+ return Expressions.call(BuiltInMethod.TIMESTAMP_TO_LONG.method, operand);
+ else if (targetType == Long.class)
+ return Expressions.call(BuiltInMethod.TIMESTAMP_TO_LONG_OPTIONAL.method, operand);
+ }
... 648473 lines suppressed ...