Skip to content

Commit

Permalink
Add EncryptSelectProjectionSupportedChecker (#32398)
Browse files Browse the repository at this point in the history
* Add EncryptSelectProjectionSupportedChecker

* Add EncryptSelectProjectionSupportedChecker
  • Loading branch information
terrymanu authored Aug 4, 2024
1 parent 20597fd commit 477229d
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -33,6 +35,8 @@ public final class EncryptSupportedSQLCheckersBuilder implements SupportedSQLChe
@Override
public Collection<SupportedSQLChecker<?, EncryptRule>> getSupportedSQLCheckers() {
return Arrays.asList(
new EncryptSelectProjectionSupportedChecker(),
new EncryptInsertSelectProjectionSupportedChecker(),
new EncryptPredicateColumnSupportedChecker(),
new EncryptOrderByItemSupportedChecker());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<InsertStatementContext, EncryptRule> {

@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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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<SelectStatementContext, EncryptRule> {

@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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import java.util.List;

/**
* Projection token generator for encrypt.
* Insert select projection token generator for encrypt.
*/
@HighFrequencyInvocation
@Setter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -76,9 +75,7 @@ public Collection<SQLToken> generateSQLTokens(final SelectStatementContext selec

private Collection<SQLToken> generateSelectSQLTokens(final SelectStatementContext selectStatementContext) {
Collection<SQLToken> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import java.util.List;

/**
* Projection token generator for encrypt.
* Select projection token generator for encrypt.
*/
@HighFrequencyInvocation
@Setter
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Integer, SelectStatementContext> 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;
}
}
Loading

0 comments on commit 477229d

Please sign in to comment.