diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 5f4326bfb740a..dd8d0772ef44c 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -16,6 +16,7 @@ 1. Kernel: Add index columns not empty judgement for IndexColumnTokenGenerator - [#33384](https://github.com/apache/shardingsphere/pull/33384) 1. SQL Parser: Support parsing Doris STRRIGHT - [#33393](https://github.com/apache/shardingsphere/pull/33393) 1. JDBC: Add show database name for JDBC when execute SHOW COMPUTE NODES - [#33437](https://github.com/apache/shardingsphere/pull/33437) +1. Kernel: Add binding to owner table - [#33533](https://github.com/apache/shardingsphere/pull/33533) ### Bug Fixes diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinder.java index b7c563bf8c020..e1d828befe82d 100644 --- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinder.java +++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinder.java @@ -34,7 +34,9 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.ColumnSegmentBoundInfo; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.TableSegmentBoundInfo; import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue; import java.util.ArrayList; @@ -82,18 +84,27 @@ public static ColumnSegment bind(final ColumnSegment segment, final SegmentType Collection tableSegmentBinderContexts = getTableSegmentBinderContexts(segment, parentSegmentType, binderContext, tableBinderContexts, outerTableBinderContexts); Optional inputColumnSegment = findInputColumnSegment(segment, parentSegmentType, tableSegmentBinderContexts, outerTableBinderContexts, binderContext); inputColumnSegment.ifPresent(optional -> result.setVariable(optional.isVariable())); + segment.getOwner().ifPresent(optional -> result.setOwner(bindOwnerTableContext(optional, inputColumnSegment.orElse(null)))); result.setColumnBoundInfo(createColumnSegmentBoundInfo(segment, inputColumnSegment.orElse(null))); return result; } private static ColumnSegment copy(final ColumnSegment segment) { ColumnSegment result = new ColumnSegment(segment.getStartIndex(), segment.getStopIndex(), segment.getIdentifier()); - segment.getOwner().ifPresent(result::setOwner); segment.getLeftParentheses().ifPresent(result::setLeftParentheses); segment.getRightParentheses().ifPresent(result::setRightParentheses); return result; } + private static OwnerSegment bindOwnerTableContext(final OwnerSegment owner, final ColumnSegment inputColumnSegment) { + IdentifierValue originalDatabase = null == inputColumnSegment ? null : inputColumnSegment.getColumnBoundInfo().getOriginalDatabase(); + IdentifierValue originalSchema = null == inputColumnSegment ? null : inputColumnSegment.getColumnBoundInfo().getOriginalSchema(); + if (originalDatabase != null && originalSchema != null) { + owner.setTableBoundInfo(new TableSegmentBoundInfo(originalDatabase, originalSchema)); + } + return owner; + } + private static Collection getTableSegmentBinderContexts(final ColumnSegment segment, final SegmentType parentSegmentType, final SQLStatementBinderContext binderContext, final Multimap tableBinderContexts, diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinderTest.java index 753dd0b6559c2..63313065ebaa1 100644 --- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinderTest.java +++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinderTest.java @@ -33,6 +33,7 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.ColumnSegmentBoundInfo; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.TableSegmentBoundInfo; import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue; import org.junit.jupiter.api.Test; @@ -43,6 +44,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; class ColumnSegmentBinderTest { @@ -134,4 +136,33 @@ void assertBindWithSameTableAliasAndDifferentProjection() { assertThat(actual.getColumnBoundInfo().getOriginalTable().getValue(), is("t_order_item")); assertThat(actual.getColumnBoundInfo().getOriginalColumn().getValue(), is("status")); } + + @Test + void assertBindOwner() { + Multimap tableBinderContexts = LinkedHashMultimap.create(); + ColumnSegment boundOrderIdColumn = new ColumnSegment(0, 0, new IdentifierValue("order_id")); + boundOrderIdColumn.setColumnBoundInfo(new ColumnSegmentBoundInfo(new IdentifierValue(DefaultDatabase.LOGIC_NAME), new IdentifierValue(DefaultDatabase.LOGIC_NAME), + new IdentifierValue("t_order"), new IdentifierValue("order_id"))); + tableBinderContexts.put(new CaseInsensitiveString("t_order"), new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderIdColumn)))); + ColumnSegment boundItemIdColumn = new ColumnSegment(0, 0, new IdentifierValue("item_id")); + boundItemIdColumn.setColumnBoundInfo(new ColumnSegmentBoundInfo(new IdentifierValue(DefaultDatabase.LOGIC_NAME), new IdentifierValue(DefaultDatabase.LOGIC_NAME), + new IdentifierValue("t_order_item"), new IdentifierValue("item_id"))); + tableBinderContexts.put(new CaseInsensitiveString("t_order_item"), new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundItemIdColumn)))); + ColumnSegment columnSegment = new ColumnSegment(0, 0, new IdentifierValue("order_id")); + columnSegment.setOwner(new OwnerSegment(0, 0, new IdentifierValue("t_order"))); + SQLStatementBinderContext binderContext = + new SQLStatementBinderContext(mock(ShardingSphereMetaData.class), DefaultDatabase.LOGIC_NAME, TypedSPILoader.getService(DatabaseType.class, "FIXTURE"), Collections.emptySet()); + ColumnSegment actual = ColumnSegmentBinder.bind(columnSegment, SegmentType.JOIN_ON, binderContext, tableBinderContexts, LinkedHashMultimap.create()); + assertTrue(actual.getOwner().isPresent()); + assertTrue(actual.getOwner().get().getTableBoundInfo().isPresent()); + TableSegmentBoundInfo actualTableBoundInfo = actual.getOwner().get().getTableBoundInfo().get(); + assertThat(actualTableBoundInfo.getOriginalDatabase().getValue(), is(DefaultDatabase.LOGIC_NAME)); + assertThat(actualTableBoundInfo.getOriginalSchema().getValue(), is(DefaultDatabase.LOGIC_NAME)); + assertNotNull(actual.getColumnBoundInfo()); + assertNull(actual.getOtherUsingColumnBoundInfo()); + assertThat(actual.getColumnBoundInfo().getOriginalDatabase().getValue(), is(DefaultDatabase.LOGIC_NAME)); + assertThat(actual.getColumnBoundInfo().getOriginalSchema().getValue(), is(DefaultDatabase.LOGIC_NAME)); + assertThat(actual.getColumnBoundInfo().getOriginalTable().getValue(), is("t_order")); + assertThat(actual.getColumnBoundInfo().getOriginalColumn().getValue(), is("order_id")); + } } diff --git a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/OwnerSegment.java b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/OwnerSegment.java index 9dcc0d89efcfc..486514a734851 100644 --- a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/OwnerSegment.java +++ b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/OwnerSegment.java @@ -21,6 +21,7 @@ import lombok.RequiredArgsConstructor; import lombok.Setter; import org.apache.shardingsphere.sql.parser.statement.core.segment.SQLSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.TableSegmentBoundInfo; import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue; import java.util.Optional; @@ -41,6 +42,8 @@ public final class OwnerSegment implements SQLSegment { private OwnerSegment owner; + private TableSegmentBoundInfo tableBoundInfo; + /** * Get owner. * @@ -49,4 +52,13 @@ public final class OwnerSegment implements SQLSegment { public Optional getOwner() { return Optional.ofNullable(owner); } + + /** + * Get table bound info. + * + * @return table bound info + */ + public Optional getTableBoundInfo() { + return Optional.ofNullable(tableBoundInfo); + } } diff --git a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/bound/TableSegmentBoundInfo.java b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/bound/TableSegmentBoundInfo.java new file mode 100644 index 0000000000000..97ec0c7f8aaf5 --- /dev/null +++ b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/bound/TableSegmentBoundInfo.java @@ -0,0 +1,34 @@ +/* + * 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.shardingsphere.sql.parser.statement.core.segment.generic.bound; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue; + +/** + * Table name bound info. + */ +@RequiredArgsConstructor +@Getter +public final class TableSegmentBoundInfo { + + private final IdentifierValue originalDatabase; + + private final IdentifierValue originalSchema; +} diff --git a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/table/TableNameSegment.java b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/table/TableNameSegment.java index c5b1140b75aa0..d12bf30caad43 100644 --- a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/table/TableNameSegment.java +++ b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/table/TableNameSegment.java @@ -21,6 +21,7 @@ import lombok.RequiredArgsConstructor; import lombok.Setter; import org.apache.shardingsphere.sql.parser.statement.core.segment.SQLSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.TableSegmentBoundInfo; import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue; /** @@ -36,4 +37,6 @@ public final class TableNameSegment implements SQLSegment { private final int stopIndex; private final IdentifierValue identifier; + + private TableSegmentBoundInfo tableBoundInfo; } diff --git a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/util/TableExtractor.java b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/util/TableExtractor.java index 7cc6bfe08c25b..ecbeb7bd696b0 100644 --- a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/util/TableExtractor.java +++ b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/util/TableExtractor.java @@ -283,7 +283,9 @@ private void extractTablesFromColumnSegments(final Collection col for (ColumnSegment each : columnSegments) { if (each.getOwner().isPresent() && needRewrite(each.getOwner().get())) { OwnerSegment ownerSegment = each.getOwner().get(); - rewriteTables.add(new SimpleTableSegment(new TableNameSegment(ownerSegment.getStartIndex(), ownerSegment.getStopIndex(), ownerSegment.getIdentifier()))); + TableNameSegment tableSegment = new TableNameSegment(ownerSegment.getStartIndex(), ownerSegment.getStopIndex(), ownerSegment.getIdentifier()); + ownerSegment.getTableBoundInfo().ifPresent(tableSegment::setTableBoundInfo); + rewriteTables.add(new SimpleTableSegment(tableSegment)); } } }