diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptSupportedSQLCheckersBuilder.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptSupportedSQLCheckersBuilder.java index 02351510cb682..971e7d4e170f3 100644 --- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptSupportedSQLCheckersBuilder.java +++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptSupportedSQLCheckersBuilder.java @@ -17,6 +17,8 @@ package org.apache.shardingsphere.encrypt.checker.sql; +import org.apache.shardingsphere.encrypt.checker.sql.projection.EncryptInsertSelectProjectionSupportedChecker; +import org.apache.shardingsphere.encrypt.checker.sql.projection.EncryptSelectProjectionSupportedChecker; import org.apache.shardingsphere.encrypt.constant.EncryptOrder; import org.apache.shardingsphere.encrypt.rule.EncryptRule; import org.apache.shardingsphere.infra.checker.SupportedSQLChecker; @@ -33,6 +35,8 @@ public final class EncryptSupportedSQLCheckersBuilder implements SupportedSQLChe @Override public Collection> getSupportedSQLCheckers() { return Arrays.asList( + new EncryptSelectProjectionSupportedChecker(), + new EncryptInsertSelectProjectionSupportedChecker(), new EncryptPredicateColumnSupportedChecker(), new EncryptOrderByItemSupportedChecker()); } diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/projection/EncryptInsertSelectProjectionSupportedChecker.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/projection/EncryptInsertSelectProjectionSupportedChecker.java new file mode 100644 index 0000000000000..64ef9467eeaeb --- /dev/null +++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/projection/EncryptInsertSelectProjectionSupportedChecker.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.shardingsphere.encrypt.checker.sql.projection; + +import org.apache.shardingsphere.encrypt.rule.EncryptRule; +import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation; +import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext; +import org.apache.shardingsphere.infra.binder.context.statement.dml.InsertStatementContext; +import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext; +import org.apache.shardingsphere.infra.checker.SupportedSQLChecker; +import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionSegment; + +/** + * Insert select projection supported checker for encrypt. + */ +@HighFrequencyInvocation +public final class EncryptInsertSelectProjectionSupportedChecker implements SupportedSQLChecker { + + @Override + public boolean isCheck(final SQLStatementContext sqlStatementContext) { + return sqlStatementContext instanceof InsertStatementContext && null != ((InsertStatementContext) sqlStatementContext).getInsertSelectContext(); + } + + @Override + public void check(final EncryptRule encryptRule, final ShardingSphereSchema schema, final InsertStatementContext sqlStatementContext) { + checkSelect(encryptRule, sqlStatementContext.getInsertSelectContext().getSelectStatementContext()); + for (SelectStatementContext each : sqlStatementContext.getInsertSelectContext().getSelectStatementContext().getSubqueryContexts().values()) { + checkSelect(encryptRule, each); + } + } + + private void checkSelect(final EncryptRule encryptRule, final SelectStatementContext selectStatementContext) { + EncryptProjectionRewriteSupportedChecker.checkNotContainEncryptProjectionInCombineSegment(encryptRule, selectStatementContext); + for (ProjectionSegment each : selectStatementContext.getSqlStatement().getProjections().getProjections()) { + EncryptProjectionRewriteSupportedChecker.checkNotContainEncryptShorthandExpandWithSubqueryStatement(selectStatementContext, each); + } + } +} diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/checker/EncryptProjectionRewriteSupportedChecker.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/projection/EncryptProjectionRewriteSupportedChecker.java similarity index 98% rename from features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/checker/EncryptProjectionRewriteSupportedChecker.java rename to features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/projection/EncryptProjectionRewriteSupportedChecker.java index 2e350753f0fdf..0118ada803488 100644 --- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/checker/EncryptProjectionRewriteSupportedChecker.java +++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/projection/EncryptProjectionRewriteSupportedChecker.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.shardingsphere.encrypt.rewrite.token.generator.projection.checker; +package org.apache.shardingsphere.encrypt.checker.sql.projection; import lombok.AccessLevel; import lombok.NoArgsConstructor; diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/projection/EncryptSelectProjectionSupportedChecker.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/projection/EncryptSelectProjectionSupportedChecker.java new file mode 100644 index 0000000000000..c646db3bec19b --- /dev/null +++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/projection/EncryptSelectProjectionSupportedChecker.java @@ -0,0 +1,53 @@ +/* + * 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.encrypt.checker.sql.projection; + +import org.apache.shardingsphere.encrypt.rule.EncryptRule; +import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation; +import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext; +import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext; +import org.apache.shardingsphere.infra.checker.SupportedSQLChecker; +import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionSegment; + +/** + * Select projection supported checker for encrypt. + */ +@HighFrequencyInvocation +public final class EncryptSelectProjectionSupportedChecker implements SupportedSQLChecker { + + @Override + public boolean isCheck(final SQLStatementContext sqlStatementContext) { + return sqlStatementContext instanceof SelectStatementContext && !((SelectStatementContext) sqlStatementContext).getTablesContext().getSimpleTables().isEmpty(); + } + + @Override + public void check(final EncryptRule encryptRule, final ShardingSphereSchema schema, final SelectStatementContext sqlStatementContext) { + checkSelect(encryptRule, sqlStatementContext); + for (SelectStatementContext each : sqlStatementContext.getSubqueryContexts().values()) { + checkSelect(encryptRule, each); + } + } + + private void checkSelect(final EncryptRule encryptRule, final SelectStatementContext selectStatementContext) { + EncryptProjectionRewriteSupportedChecker.checkNotContainEncryptProjectionInCombineSegment(encryptRule, selectStatementContext); + for (ProjectionSegment each : selectStatementContext.getSqlStatement().getProjections().getProjections()) { + EncryptProjectionRewriteSupportedChecker.checkNotContainEncryptShorthandExpandWithSubqueryStatement(selectStatementContext, each); + } + } +} diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptInsertSelectProjectionTokenGenerator.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptInsertSelectProjectionTokenGenerator.java index abeb22de74b2e..6f9f47ccd2969 100644 --- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptInsertSelectProjectionTokenGenerator.java +++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptInsertSelectProjectionTokenGenerator.java @@ -33,7 +33,7 @@ import java.util.List; /** - * Projection token generator for encrypt. + * Insert select projection token generator for encrypt. */ @HighFrequencyInvocation @Setter diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGenerator.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGenerator.java index b61382fde561b..b870cf68eb5f1 100644 --- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGenerator.java +++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGenerator.java @@ -18,7 +18,6 @@ package org.apache.shardingsphere.encrypt.rewrite.token.generator.projection; import lombok.RequiredArgsConstructor; -import org.apache.shardingsphere.encrypt.rewrite.token.generator.projection.checker.EncryptProjectionRewriteSupportedChecker; import org.apache.shardingsphere.encrypt.rule.EncryptRule; import org.apache.shardingsphere.encrypt.rule.column.EncryptColumn; import org.apache.shardingsphere.encrypt.rule.table.EncryptTable; @@ -76,9 +75,7 @@ public Collection generateSQLTokens(final SelectStatementContext selec private Collection generateSelectSQLTokens(final SelectStatementContext selectStatementContext) { Collection result = new LinkedList<>(); - EncryptProjectionRewriteSupportedChecker.checkNotContainEncryptProjectionInCombineSegment(encryptRule, selectStatementContext); for (ProjectionSegment each : selectStatementContext.getSqlStatement().getProjections().getProjections()) { - EncryptProjectionRewriteSupportedChecker.checkNotContainEncryptShorthandExpandWithSubqueryStatement(selectStatementContext, each); if (each instanceof ColumnProjectionSegment) { generateSQLToken(selectStatementContext, (ColumnProjectionSegment) each).ifPresent(result::add); } diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptSelectProjectionTokenGenerator.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptSelectProjectionTokenGenerator.java index 479842568ea70..7f7b964ba38c3 100644 --- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptSelectProjectionTokenGenerator.java +++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptSelectProjectionTokenGenerator.java @@ -33,7 +33,7 @@ import java.util.List; /** - * Projection token generator for encrypt. + * Select projection token generator for encrypt. */ @HighFrequencyInvocation @Setter diff --git a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/projection/EncryptSelectProjectionSupportedCheckerTest.java b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/projection/EncryptSelectProjectionSupportedCheckerTest.java new file mode 100644 index 0000000000000..96b52ee0bb1bb --- /dev/null +++ b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/projection/EncryptSelectProjectionSupportedCheckerTest.java @@ -0,0 +1,101 @@ +/* + * 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.encrypt.checker.sql.projection; + +import org.apache.shardingsphere.encrypt.rule.EncryptRule; +import org.apache.shardingsphere.encrypt.rule.column.EncryptColumn; +import org.apache.shardingsphere.encrypt.rule.table.EncryptTable; +import org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.ColumnProjection; +import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext; +import org.apache.shardingsphere.infra.database.mysql.type.MySQLDatabaseType; +import org.apache.shardingsphere.infra.exception.generic.UnsupportedSQLOperationException; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.combine.CombineSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ShorthandProjectionSegment; +import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class EncryptSelectProjectionSupportedCheckerTest { + + @Test + void assertCheckWhenShorthandExpandContainsSubqueryTable() { + SelectStatementContext sqlStatementContext = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); + when(sqlStatementContext.containsTableSubquery()).thenReturn(true); + when(sqlStatementContext.getSqlStatement().getProjections().getProjections()).thenReturn(Collections.singleton(new ShorthandProjectionSegment(0, 0))); + assertThrows(UnsupportedSQLOperationException.class, () -> new EncryptSelectProjectionSupportedChecker().check(mockEncryptRule(), null, sqlStatementContext)); + } + + @Test + void assertCheckWhenCombineStatementContainsEncryptColumn() { + SelectStatementContext sqlStatementContext = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); + when(sqlStatementContext.isContainsCombine()).thenReturn(true); + when(sqlStatementContext.getSqlStatement().getCombine().isPresent()).thenReturn(true); + CombineSegment combineSegment = mock(CombineSegment.class, RETURNS_DEEP_STUBS); + when(sqlStatementContext.getSqlStatement().getCombine().get()).thenReturn(combineSegment); + ColumnProjection orderIdColumn = new ColumnProjection("o", "order_id", null, new MySQLDatabaseType()); + orderIdColumn.setOriginalTable(new IdentifierValue("t_order")); + orderIdColumn.setOriginalColumn(new IdentifierValue("order_id")); + ColumnProjection userIdColumn = new ColumnProjection("o", "user_id", null, new MySQLDatabaseType()); + userIdColumn.setOriginalTable(new IdentifierValue("t_order")); + userIdColumn.setOriginalColumn(new IdentifierValue("user_id")); + SelectStatementContext leftSelectStatementContext = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); + when(leftSelectStatementContext.getProjectionsContext().getExpandProjections()).thenReturn(Arrays.asList(orderIdColumn, userIdColumn)); + ColumnProjection merchantIdColumn = new ColumnProjection("m", "merchant_id", null, new MySQLDatabaseType()); + merchantIdColumn.setOriginalTable(new IdentifierValue("t_merchant")); + merchantIdColumn.setOriginalColumn(new IdentifierValue("merchant_id")); + ColumnProjection merchantNameColumn = new ColumnProjection("m", "merchant_name", null, new MySQLDatabaseType()); + merchantNameColumn.setOriginalTable(new IdentifierValue("t_merchant")); + merchantNameColumn.setOriginalColumn(new IdentifierValue("merchant_name")); + SelectStatementContext rightSelectStatementContext = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); + when(rightSelectStatementContext.getProjectionsContext().getExpandProjections()).thenReturn(Arrays.asList(merchantIdColumn, merchantNameColumn)); + Map subqueryContexts = new LinkedHashMap<>(2, 1F); + subqueryContexts.put(0, leftSelectStatementContext); + subqueryContexts.put(1, rightSelectStatementContext); + when(sqlStatementContext.getSubqueryContexts()).thenReturn(subqueryContexts); + when(combineSegment.getLeft().getStartIndex()).thenReturn(0); + when(combineSegment.getRight().getStartIndex()).thenReturn(1); + assertThrows(UnsupportedSQLOperationException.class, () -> new EncryptSelectProjectionSupportedChecker().check(mockEncryptRule(), null, sqlStatementContext)); + } + + private EncryptRule mockEncryptRule() { + EncryptRule result = mock(EncryptRule.class, RETURNS_DEEP_STUBS); + EncryptTable encryptTable1 = mock(EncryptTable.class); + EncryptTable encryptTable2 = mock(EncryptTable.class); + when(encryptTable1.getLogicColumns()).thenReturn(Collections.singleton("mobile")); + when(encryptTable2.getLogicColumns()).thenReturn(Collections.singleton("mobile")); + when(result.findEncryptTable("doctor")).thenReturn(Optional.of(encryptTable1)); + when(result.findEncryptTable("doctor1")).thenReturn(Optional.of(encryptTable2)); + when(encryptTable1.isEncryptColumn("mobile")).thenReturn(true); + EncryptColumn encryptColumn = mock(EncryptColumn.class, RETURNS_DEEP_STUBS); + when(encryptColumn.getAssistedQuery()).thenReturn(Optional.empty()); + when(encryptTable1.getEncryptColumn("mobile")).thenReturn(encryptColumn); + when(result.findEncryptTable("t_order").isPresent()).thenReturn(true); + when(result.getEncryptTable("t_order").isEncryptColumn("order_id")).thenReturn(true); + return result; + } +} diff --git a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGeneratorTest.java b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGeneratorTest.java index 31400fcc74ee7..6a3d97649e827 100644 --- a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGeneratorTest.java +++ b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGeneratorTest.java @@ -25,15 +25,11 @@ import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext; import org.apache.shardingsphere.infra.database.core.DefaultDatabase; import org.apache.shardingsphere.infra.database.core.type.DatabaseType; -import org.apache.shardingsphere.infra.database.mysql.type.MySQLDatabaseType; -import org.apache.shardingsphere.infra.exception.generic.UnsupportedSQLOperationException; import org.apache.shardingsphere.infra.rewrite.sql.token.common.pojo.SQLToken; import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; -import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.combine.CombineSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionsSegment; -import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ShorthandProjectionSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.AliasSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.ColumnSegmentBoundInfo; @@ -46,13 +42,10 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; import java.util.Optional; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -147,44 +140,4 @@ void assertGenerateSQLTokensWhenOwnerMatchTableName() { Collection actual = generator.generateSQLTokens(sqlStatementContext); assertThat(actual.size(), is(1)); } - - @Test - void assertGenerateSQLTokensWhenShorthandExpandContainsSubqueryTable() { - SelectStatementContext sqlStatementContext = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); - when(sqlStatementContext.containsTableSubquery()).thenReturn(true); - when(sqlStatementContext.getSqlStatement().getProjections().getProjections()).thenReturn(Collections.singleton(new ShorthandProjectionSegment(0, 0))); - assertThrows(UnsupportedSQLOperationException.class, () -> generator.generateSQLTokens(sqlStatementContext)); - } - - @Test - void assertGenerateSQLTokensWhenCombineStatementContainsEncryptColumn() { - SelectStatementContext sqlStatementContext = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); - when(sqlStatementContext.isContainsCombine()).thenReturn(true); - when(sqlStatementContext.getSqlStatement().getCombine().isPresent()).thenReturn(true); - CombineSegment combineSegment = mock(CombineSegment.class, RETURNS_DEEP_STUBS); - when(sqlStatementContext.getSqlStatement().getCombine().get()).thenReturn(combineSegment); - ColumnProjection orderIdColumn = new ColumnProjection("o", "order_id", null, new MySQLDatabaseType()); - orderIdColumn.setOriginalTable(new IdentifierValue("t_order")); - orderIdColumn.setOriginalColumn(new IdentifierValue("order_id")); - ColumnProjection userIdColumn = new ColumnProjection("o", "user_id", null, new MySQLDatabaseType()); - userIdColumn.setOriginalTable(new IdentifierValue("t_order")); - userIdColumn.setOriginalColumn(new IdentifierValue("user_id")); - SelectStatementContext leftSelectStatementContext = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); - when(leftSelectStatementContext.getProjectionsContext().getExpandProjections()).thenReturn(Arrays.asList(orderIdColumn, userIdColumn)); - ColumnProjection merchantIdColumn = new ColumnProjection("m", "merchant_id", null, new MySQLDatabaseType()); - merchantIdColumn.setOriginalTable(new IdentifierValue("t_merchant")); - merchantIdColumn.setOriginalColumn(new IdentifierValue("merchant_id")); - ColumnProjection merchantNameColumn = new ColumnProjection("m", "merchant_name", null, new MySQLDatabaseType()); - merchantNameColumn.setOriginalTable(new IdentifierValue("t_merchant")); - merchantNameColumn.setOriginalColumn(new IdentifierValue("merchant_name")); - SelectStatementContext rightSelectStatementContext = mock(SelectStatementContext.class, RETURNS_DEEP_STUBS); - when(rightSelectStatementContext.getProjectionsContext().getExpandProjections()).thenReturn(Arrays.asList(merchantIdColumn, merchantNameColumn)); - Map subqueryContexts = new LinkedHashMap<>(2, 1F); - subqueryContexts.put(0, leftSelectStatementContext); - subqueryContexts.put(1, rightSelectStatementContext); - when(sqlStatementContext.getSubqueryContexts()).thenReturn(subqueryContexts); - when(combineSegment.getLeft().getStartIndex()).thenReturn(0); - when(combineSegment.getRight().getStartIndex()).thenReturn(1); - assertThrows(UnsupportedSQLOperationException.class, () -> generator.generateSQLTokens(sqlStatementContext)); - } }