This is an automated email from the ASF dual-hosted git repository. tkalkirill pushed a commit to branch ignite-29015 in repository https://gitbox.apache.org/repos/asf/ignite.git
commit 147d14116342e063304d25aece35d509a6bf1f3e Author: Kirill Tkalenko <[email protected]> AuthorDate: Wed Aug 26 14:06:12 2026 +0300 IGNITE-29015 Wip --- .../query/calcite/exec/LogicalRelImplementor.java | 6 +- .../query/calcite/prepare/IgnitePlanner.java | 2 +- .../calcite/prepare/IgniteSqlPaginationPolicy.java | 39 ------------ .../query/calcite/prepare/IgniteSqlSemantics.java | 71 ++++++++++++++++++++++ .../query/calcite/prepare/IgniteSqlValidator.java | 10 +-- .../query/calcite/rule/SortConverterRule.java | 6 +- .../OperatorsExtensionIntegrationTest.java | 6 +- .../calcite/planner/LimitOffsetPlannerTest.java | 6 +- 8 files changed, 91 insertions(+), 55 deletions(-) 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 index 5b7d70934ab..ed04f327eb3 100644 --- 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 @@ -85,7 +85,7 @@ import org.apache.ignite.internal.processors.query.calcite.exec.rel.UnionAllNode import org.apache.ignite.internal.processors.query.calcite.exec.rel.WindowNode; 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.prepare.IgniteSqlPaginationPolicy; +import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteSqlSemantics; import org.apache.ignite.internal.processors.query.calcite.prepare.bounds.SearchBounds; import org.apache.ignite.internal.processors.query.calcite.rel.IgniteCollect; import org.apache.ignite.internal.processors.query.calcite.rel.IgniteCorrelatedNestedLoopJoin; @@ -1094,8 +1094,8 @@ public class LogicalRelImplementor<Row> implements IgniteRelVisitor<Node<Row>> { if (paramAsDecimal.signum() < 0) throw new IllegalArgumentException("Negative value for " + op); - IgniteSqlPaginationPolicy pagPlc = ctx.unwrap(IgniteSqlPaginationPolicy.class); - return IgniteSqlPaginationPolicy.convertToLongExact(paramAsDecimal, pagPlc); + IgniteSqlSemantics sem = ctx.unwrap(IgniteSqlSemantics.class); + return IgniteSqlSemantics.convertPaginationValueToLong(paramAsDecimal, sem); } catch (RuntimeException ex) { throw new IgniteSQLException(IgniteResource.INSTANCE.illegalFetchLimit(op).str(), diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgnitePlanner.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgnitePlanner.java index 2ed2fe2ce42..9563ccd25ed 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgnitePlanner.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgnitePlanner.java @@ -816,7 +816,7 @@ public class IgnitePlanner implements Planner, RelOptTable.ViewExpander { typeFactory, validatorCfg, ctx.parameters(), - ctx.unwrap(IgniteSqlPaginationPolicy.class) + ctx.unwrap(IgniteSqlSemantics.class) ); } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlPaginationPolicy.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlPaginationPolicy.java deleted file mode 100644 index e7f81e9456e..00000000000 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlPaginationPolicy.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.prepare; - -import java.math.RoundingMode; -import org.apache.calcite.plan.Context; -import org.apache.calcite.tools.Frameworks; -import org.apache.ignite.internal.processors.query.calcite.util.IgniteMath; -import org.jetbrains.annotations.Nullable; - -/** - * Defines a policy for processing values of SQL pagination clauses: LIMIT, FETCH, and OFFSET. - * - * <p>Custom instance can be supplied through {@link Frameworks.ConfigBuilder#context(Context)}.</p> - */ -@FunctionalInterface -public interface IgniteSqlPaginationPolicy { - /** Returns the rounding mode for FETCH, LIMIT and OFFSET values. */ - RoundingMode roundingMode(); - - /** Rounds the given value according to the specified policy and converts it to {@code long}. */ - static long convertToLongExact(Number value, @Nullable IgniteSqlPaginationPolicy policy) { - return policy == null ? IgniteMath.convertToLongExact(value) : IgniteMath.convertToLongExact(value, policy.roundingMode()); - } -} diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlSemantics.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlSemantics.java new file mode 100644 index 00000000000..52db5be64fe --- /dev/null +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlSemantics.java @@ -0,0 +1,71 @@ +/* + * 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.prepare; + +import java.math.RoundingMode; +import java.util.Objects; +import org.apache.ignite.internal.processors.query.calcite.util.IgniteMath; +import org.jetbrains.annotations.Nullable; + +/** Fine-grained settings that affect SQL semantics. */ +public final class IgniteSqlSemantics { + /** */ + private final RoundingMode paginationRoundingMode; + + /** */ + private IgniteSqlSemantics(Builder builder) { + paginationRoundingMode = builder.paginationRoundingMode; + } + + /** Returns a new builder initialized with default settings. */ + public static Builder builder() { + return new Builder(); + } + + /** Returns the rounding mode for FETCH, LIMIT and OFFSET values. */ + public RoundingMode paginationRoundingMode() { + return paginationRoundingMode; + } + + /** */ + public static final class Builder { + /** */ + private RoundingMode paginationRoundingMode = IgniteMath.NUMERIC_ROUNDING_MODE; + + /** */ + private Builder() { + // No-op. + } + + /** Sets the rounding mode for FETCH, LIMIT and OFFSET values. */ + public Builder paginationRoundingMode(RoundingMode paginationRoundingMode) { + this.paginationRoundingMode = Objects.requireNonNull(paginationRoundingMode); + + return this; + } + + /** */ + public IgniteSqlSemantics build() { + return new IgniteSqlSemantics(this); + } + } + + /** Rounds the given pagination value according to the specified SQL semantics and converts it to {@code long}. */ + public static long convertPaginationValueToLong(Number value, @Nullable IgniteSqlSemantics sem) { + return sem == null ? IgniteMath.convertToLongExact(value) : IgniteMath.convertToLongExact(value, sem.paginationRoundingMode()); + } +} diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java index 5656165a221..d7af46290f4 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/prepare/IgniteSqlValidator.java @@ -115,7 +115,7 @@ public class IgniteSqlValidator extends SqlValidatorImpl { private final RelDataType nullType; /** */ - private final @Nullable IgniteSqlPaginationPolicy pagPlc; + private final @Nullable IgniteSqlSemantics sqlSem; /** * Creates a validator. @@ -125,7 +125,7 @@ public class IgniteSqlValidator extends SqlValidatorImpl { * @param typeFactory Type factory. * @param cfg Config. * @param parameters Dynamic parameters. - * @param pagPlc Pagination policy. + * @param sqlSem SQL semantics. */ public IgniteSqlValidator( SqlOperatorTable opTab, @@ -133,12 +133,12 @@ public class IgniteSqlValidator extends SqlValidatorImpl { IgniteTypeFactory typeFactory, SqlValidator.Config cfg, @Nullable Object[] parameters, - @Nullable IgniteSqlPaginationPolicy pagPlc + @Nullable IgniteSqlSemantics sqlSem ) { super(opTab, catalogReader, typeFactory, cfg); this.parameters = parameters; - this.pagPlc = pagPlc; + this.sqlSem = sqlSem; nullType = typeFactory.createSqlType(SqlTypeName.NULL); } @@ -390,7 +390,7 @@ public class IgniteSqlValidator extends SqlValidatorImpl { if (val.signum() < 0) throw new IllegalArgumentException("Negative value for " + nodeName); - IgniteSqlPaginationPolicy.convertToLongExact(val, pagPlc); + IgniteSqlSemantics.convertPaginationValueToLong(val, sqlSem); } catch (RuntimeException e) { throw newValidationError(n, IgniteResource.INSTANCE.illegalFetchLimit(nodeName)); diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/SortConverterRule.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/SortConverterRule.java index 9cd4c23cc3f..a394745c900 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/SortConverterRule.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/rule/SortConverterRule.java @@ -35,7 +35,7 @@ import org.apache.calcite.rex.RexDynamicParam; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexNode; import org.apache.calcite.rex.RexUtil; -import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteSqlPaginationPolicy; +import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteSqlSemantics; import org.apache.ignite.internal.processors.query.calcite.rel.IgniteConvention; import org.apache.ignite.internal.processors.query.calcite.rel.IgniteLimit; import org.apache.ignite.internal.processors.query.calcite.rel.IgniteSort; @@ -144,10 +144,10 @@ public class SortConverterRule extends RelRule<SortConverterRule.Config> { return false; // SortNode does not accept zero FETCH; the outer IgniteLimit handles it. - IgniteSqlPaginationPolicy pagPlc = sort.getCluster().getPlanner().getContext().unwrap(IgniteSqlPaginationPolicy.class); + IgniteSqlSemantics sem = sort.getCluster().getPlanner().getContext().unwrap(IgniteSqlSemantics.class); try { - return IgniteSqlPaginationPolicy.convertToLongExact(fetchVal, pagPlc) > 0; + return IgniteSqlSemantics.convertPaginationValueToLong(fetchVal, sem) > 0; } catch (ArithmeticException ignored) { // The outer IgniteLimit will report invalid FETCH during execution. diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/OperatorsExtensionIntegrationTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/OperatorsExtensionIntegrationTest.java index 43f5a9248e1..35a6c1bf96c 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/OperatorsExtensionIntegrationTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/OperatorsExtensionIntegrationTest.java @@ -67,7 +67,7 @@ import org.apache.ignite.internal.processors.query.calcite.exec.exp.agg.Accumula import org.apache.ignite.internal.processors.query.calcite.exec.exp.agg.Accumulators; import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteConvertletTable; import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteSqlNodeRewriter; -import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteSqlPaginationPolicy; +import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteSqlSemantics; import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteSqlValidator; import org.apache.ignite.internal.processors.query.calcite.type.IgniteTypeFactory; import org.apache.ignite.plugin.AbstractTestPluginProvider; @@ -98,7 +98,9 @@ public class OperatorsExtensionIntegrationTest extends AbstractBasicIntegrationT .withSqlNodeRewriter(new SqlRewriter())) .context(Contexts.chain( CalciteQueryProcessor.FRAMEWORK_CONFIG.getContext(), - Contexts.of((IgniteSqlPaginationPolicy)() -> RoundingMode.DOWN), + Contexts.of(IgniteSqlSemantics.builder() + .paginationRoundingMode(RoundingMode.DOWN) + .build()), Contexts.of(new AccumulatorFactoryProviderImpl()))) .build(); diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/LimitOffsetPlannerTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/LimitOffsetPlannerTest.java index dc876471513..98a91eb61de 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/LimitOffsetPlannerTest.java +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/planner/LimitOffsetPlannerTest.java @@ -27,7 +27,7 @@ import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.sql.SqlNode; import org.apache.calcite.util.ImmutableIntList; import org.apache.ignite.internal.processors.query.calcite.prepare.IgnitePlanner; -import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteSqlPaginationPolicy; +import org.apache.ignite.internal.processors.query.calcite.prepare.IgniteSqlSemantics; import org.apache.ignite.internal.processors.query.calcite.prepare.PlanningContext; import org.apache.ignite.internal.processors.query.calcite.rel.IgniteExchange; import org.apache.ignite.internal.processors.query.calcite.rel.IgniteIndexScan; @@ -102,7 +102,9 @@ public class LimitOffsetPlannerTest extends AbstractPlannerTest { .query("SELECT * FROM TEST ORDER BY ID OFFSET 1 ROWS " + "FETCH FIRST (ABS(0.6)) ROWS ONLY") .schema(publicSchema) - .additionalCtx(Contexts.of((IgniteSqlPaginationPolicy)() -> RoundingMode.DOWN)), + .additionalCtx(Contexts.of(IgniteSqlSemantics.builder() + .paginationRoundingMode(RoundingMode.DOWN) + .build())), isInstanceOf(IgniteLimit.class) .and(limit -> limit.offset() != null && limit.fetch() != null) .and(input(isInstanceOf(IgniteExchange.class)
