You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2024/08/04 15:23:12 UTC
(shardingsphere) branch master updated: Add EncryptPredicateColumnSupportedChecker (#32397)
This is an automated email from the ASF dual-hosted git repository.
zhaojinchao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 20597fd1b69 Add EncryptPredicateColumnSupportedChecker (#32397)
20597fd1b69 is described below
commit 20597fd1b69639d70f37de1439ecd67e0af355ae
Author: Liang Zhang <zh...@apache.org>
AuthorDate: Sun Aug 4 23:23:05 2024 +0800
Add EncryptPredicateColumnSupportedChecker (#32397)
---
.../EncryptPredicateColumnSupportedChecker.java | 99 ++++++++++++++++++++++
.../sql/EncryptSupportedSQLCheckersBuilder.java | 6 +-
.../EncryptPredicateColumnTokenGenerator.java | 17 ++--
...ncryptPredicateColumnSupportedCheckerTest.java} | 32 ++-----
.../EncryptPredicateColumnTokenGeneratorTest.java | 8 --
5 files changed, 118 insertions(+), 44 deletions(-)
diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptPredicateColumnSupportedChecker.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptPredicateColumnSupportedChecker.java
new file mode 100644
index 00000000000..a76c6816a7f
--- /dev/null
+++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptPredicateColumnSupportedChecker.java
@@ -0,0 +1,99 @@
+/*
+ * 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;
+
+import org.apache.shardingsphere.encrypt.exception.metadata.MissingMatchedEncryptQueryAlgorithmException;
+import org.apache.shardingsphere.encrypt.rewrite.token.comparator.JoinConditionsEncryptorComparator;
+import org.apache.shardingsphere.encrypt.rule.EncryptRule;
+import org.apache.shardingsphere.encrypt.rule.table.EncryptTable;
+import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation;
+import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
+import org.apache.shardingsphere.infra.binder.context.type.TableAvailable;
+import org.apache.shardingsphere.infra.binder.context.type.WhereAvailable;
+import org.apache.shardingsphere.infra.checker.SupportedSQLChecker;
+import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
+import org.apache.shardingsphere.infra.exception.generic.UnsupportedSQLOperationException;
+import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.AndPredicate;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.util.ExpressionExtractUtils;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Predicate column supported checker for encrypt.
+ */
+@HighFrequencyInvocation
+public final class EncryptPredicateColumnSupportedChecker implements SupportedSQLChecker<SQLStatementContext, EncryptRule> {
+
+ @Override
+ public boolean isCheck(final SQLStatementContext sqlStatementContext) {
+ return sqlStatementContext instanceof WhereAvailable && !((WhereAvailable) sqlStatementContext).getWhereSegments().isEmpty();
+ }
+
+ @Override
+ public void check(final EncryptRule encryptRule, final ShardingSphereSchema schema, final SQLStatementContext sqlStatementContext) {
+ ShardingSpherePreconditions.checkState(JoinConditionsEncryptorComparator.isSame(((WhereAvailable) sqlStatementContext).getJoinConditions(), encryptRule),
+ () -> new UnsupportedSQLOperationException("Can not use different encryptor in join condition"));
+ check(encryptRule, schema, (WhereAvailable) sqlStatementContext);
+ }
+
+ private void check(final EncryptRule encryptRule, final ShardingSphereSchema schema, final WhereAvailable sqlStatementContext) {
+ Map<String, String> columnExpressionTableNames = ((TableAvailable) sqlStatementContext).getTablesContext().findTableNames(sqlStatementContext.getColumnSegments(), schema);
+ for (ColumnSegment each : sqlStatementContext.getColumnSegments()) {
+ Optional<EncryptTable> encryptTable = encryptRule.findEncryptTable(columnExpressionTableNames.getOrDefault(each.getExpression(), ""));
+ String columnName = each.getIdentifier().getValue();
+ if (encryptTable.isPresent() && encryptTable.get().isEncryptColumn(columnName) && includesLike(sqlStatementContext.getWhereSegments(), each)) {
+ String tableName = encryptTable.get().getTable();
+ ShardingSpherePreconditions.checkState(
+ encryptTable.get().getEncryptColumn(columnName).getLikeQuery().isPresent(), () -> new MissingMatchedEncryptQueryAlgorithmException(tableName, columnName, "LIKE"));
+ }
+ }
+ }
+
+ private boolean includesLike(final Collection<WhereSegment> whereSegments, final ColumnSegment targetColumnSegment) {
+ for (WhereSegment each : whereSegments) {
+ Collection<AndPredicate> andPredicates = ExpressionExtractUtils.getAndPredicates(each.getExpr());
+ for (AndPredicate andPredicate : andPredicates) {
+ if (isLikeColumnSegment(andPredicate, targetColumnSegment)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean isLikeColumnSegment(final AndPredicate andPredicate, final ColumnSegment targetColumnSegment) {
+ for (ExpressionSegment each : andPredicate.getPredicates()) {
+ if (each instanceof BinaryOperationExpression
+ && "LIKE".equalsIgnoreCase(((BinaryOperationExpression) each).getOperator()) && isSameColumnSegment(((BinaryOperationExpression) each).getLeft(), targetColumnSegment)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isSameColumnSegment(final ExpressionSegment columnSegment, final ColumnSegment targetColumnSegment) {
+ return columnSegment instanceof ColumnSegment && columnSegment.getStartIndex() == targetColumnSegment.getStartIndex() && columnSegment.getStopIndex() == targetColumnSegment.getStopIndex();
+ }
+}
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 3f89b02ff42..02351510cb6 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
@@ -22,8 +22,8 @@ import org.apache.shardingsphere.encrypt.rule.EncryptRule;
import org.apache.shardingsphere.infra.checker.SupportedSQLChecker;
import org.apache.shardingsphere.infra.checker.SupportedSQLCheckersBuilder;
+import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
/**
* Encrypt SQL supported checker factory.
@@ -32,7 +32,9 @@ public final class EncryptSupportedSQLCheckersBuilder implements SupportedSQLChe
@Override
public Collection<SupportedSQLChecker<?, EncryptRule>> getSupportedSQLCheckers() {
- return Collections.singleton(new EncryptOrderByItemSupportedChecker());
+ return Arrays.asList(
+ new EncryptPredicateColumnSupportedChecker(),
+ new EncryptOrderByItemSupportedChecker());
}
@Override
diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateColumnTokenGenerator.java b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateColumnTokenGenerator.java
index ad9346c09ae..76bec710ddc 100644
--- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateColumnTokenGenerator.java
+++ b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateColumnTokenGenerator.java
@@ -17,10 +17,9 @@
package org.apache.shardingsphere.encrypt.rewrite.token.generator.predicate;
+import com.google.common.base.Preconditions;
import lombok.Setter;
-import org.apache.shardingsphere.encrypt.exception.metadata.MissingMatchedEncryptQueryAlgorithmException;
import org.apache.shardingsphere.encrypt.rewrite.aware.EncryptRuleAware;
-import org.apache.shardingsphere.encrypt.rewrite.token.comparator.JoinConditionsEncryptorComparator;
import org.apache.shardingsphere.encrypt.rule.EncryptRule;
import org.apache.shardingsphere.encrypt.rule.column.EncryptColumn;
import org.apache.shardingsphere.encrypt.rule.column.item.LikeQueryColumnItem;
@@ -33,8 +32,6 @@ import org.apache.shardingsphere.infra.binder.context.type.TableAvailable;
import org.apache.shardingsphere.infra.binder.context.type.WhereAvailable;
import org.apache.shardingsphere.infra.database.core.metadata.database.enums.QuoteCharacter;
import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
-import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
-import org.apache.shardingsphere.infra.exception.generic.UnsupportedSQLOperationException;
import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
import org.apache.shardingsphere.infra.rewrite.sql.token.common.generator.CollectionSQLTokenGenerator;
import org.apache.shardingsphere.infra.rewrite.sql.token.common.generator.aware.SchemaMetaDataAware;
@@ -74,8 +71,6 @@ public final class EncryptPredicateColumnTokenGenerator implements CollectionSQL
@Override
public Collection<SQLToken> generateSQLTokens(final SQLStatementContext sqlStatementContext) {
- ShardingSpherePreconditions.checkState(JoinConditionsEncryptorComparator.isSame(((WhereAvailable) sqlStatementContext).getJoinConditions(), encryptRule),
- () -> new UnsupportedSQLOperationException("Can not use different encryptor in join condition"));
Collection<ColumnSegment> columnSegments = ((WhereAvailable) sqlStatementContext).getColumnSegments();
Collection<WhereSegment> whereSegments = ((WhereAvailable) sqlStatementContext).getWhereSegments();
ShardingSphereSchema schema = ((TableAvailable) sqlStatementContext).getTablesContext().getSchemaName().map(schemas::get).orElseGet(() -> defaultSchema);
@@ -90,21 +85,21 @@ public final class EncryptPredicateColumnTokenGenerator implements CollectionSQL
String tableName = columnExpressionTableNames.getOrDefault(each.getExpression(), "");
Optional<EncryptTable> encryptTable = encryptRule.findEncryptTable(tableName);
if (encryptTable.isPresent() && encryptTable.get().isEncryptColumn(each.getIdentifier().getValue())) {
- result.add(buildSubstitutableColumnNameToken(encryptTable.get().getTable(), encryptTable.get().getEncryptColumn(each.getIdentifier().getValue()), each, whereSegments, databaseType));
+ result.add(buildSubstitutableColumnNameToken(encryptTable.get().getEncryptColumn(each.getIdentifier().getValue()), each, whereSegments, databaseType));
}
}
return result;
}
- private SubstitutableColumnNameToken buildSubstitutableColumnNameToken(final String tableName, final EncryptColumn encryptColumn,
+ private SubstitutableColumnNameToken buildSubstitutableColumnNameToken(final EncryptColumn encryptColumn,
final ColumnSegment columnSegment, final Collection<WhereSegment> whereSegments, final DatabaseType databaseType) {
int startIndex = columnSegment.getOwner().isPresent() ? columnSegment.getOwner().get().getStopIndex() + 2 : columnSegment.getStartIndex();
int stopIndex = columnSegment.getStopIndex();
if (includesLike(whereSegments, columnSegment)) {
- LikeQueryColumnItem likeQueryColumnItem = encryptColumn.getLikeQuery().orElseThrow(
- () -> new MissingMatchedEncryptQueryAlgorithmException(tableName, columnSegment.getIdentifier().getValue(), "LIKE"));
+ Optional<LikeQueryColumnItem> likeQueryColumnItem = encryptColumn.getLikeQuery();
+ Preconditions.checkState(likeQueryColumnItem.isPresent());
return new SubstitutableColumnNameToken(
- startIndex, stopIndex, createColumnProjections(likeQueryColumnItem.getName(), columnSegment.getIdentifier().getQuoteCharacter(), databaseType), databaseType);
+ startIndex, stopIndex, createColumnProjections(likeQueryColumnItem.get().getName(), columnSegment.getIdentifier().getQuoteCharacter(), databaseType), databaseType);
}
Collection<Projection> columnProjections =
encryptColumn.getAssistedQuery().map(optional -> createColumnProjections(optional.getName(), columnSegment.getIdentifier().getQuoteCharacter(), databaseType))
diff --git a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptSupportedSQLCheckersBuilder.java b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptPredicateColumnSupportedCheckerTest.java
similarity index 50%
copy from features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptSupportedSQLCheckersBuilder.java
copy to features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptPredicateColumnSupportedCheckerTest.java
index 3f89b02ff42..322a8142cde 100644
--- a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptSupportedSQLCheckersBuilder.java
+++ b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/checker/sql/EncryptPredicateColumnSupportedCheckerTest.java
@@ -17,31 +17,17 @@
package org.apache.shardingsphere.encrypt.checker.sql;
-import org.apache.shardingsphere.encrypt.constant.EncryptOrder;
-import org.apache.shardingsphere.encrypt.rule.EncryptRule;
-import org.apache.shardingsphere.infra.checker.SupportedSQLChecker;
-import org.apache.shardingsphere.infra.checker.SupportedSQLCheckersBuilder;
+import org.apache.shardingsphere.encrypt.rewrite.token.generator.fixture.EncryptGeneratorFixtureBuilder;
+import org.apache.shardingsphere.infra.exception.generic.UnsupportedSQLOperationException;
+import org.junit.jupiter.api.Test;
-import java.util.Collection;
-import java.util.Collections;
+import static org.junit.jupiter.api.Assertions.assertThrows;
-/**
- * Encrypt SQL supported checker factory.
- */
-public final class EncryptSupportedSQLCheckersBuilder implements SupportedSQLCheckersBuilder<EncryptRule> {
-
- @Override
- public Collection<SupportedSQLChecker<?, EncryptRule>> getSupportedSQLCheckers() {
- return Collections.singleton(new EncryptOrderByItemSupportedChecker());
- }
-
- @Override
- public int getOrder() {
- return EncryptOrder.ORDER;
- }
+class EncryptPredicateColumnSupportedCheckerTest {
- @Override
- public Class<EncryptRule> getTypeClass() {
- return EncryptRule.class;
+ @Test
+ void assertGenerateSQLTokensWhenJoinConditionUseDifferentEncryptor() {
+ assertThrows(UnsupportedSQLOperationException.class,
+ () -> new EncryptPredicateColumnSupportedChecker().check(EncryptGeneratorFixtureBuilder.createEncryptRule(), null, EncryptGeneratorFixtureBuilder.createSelectStatementContext()));
}
}
diff --git a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateColumnTokenGeneratorTest.java b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateColumnTokenGeneratorTest.java
index 1794045d48f..f0eeedc0688 100644
--- a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateColumnTokenGeneratorTest.java
+++ b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateColumnTokenGeneratorTest.java
@@ -18,7 +18,6 @@
package org.apache.shardingsphere.encrypt.rewrite.token.generator.predicate;
import org.apache.shardingsphere.encrypt.rewrite.token.generator.fixture.EncryptGeneratorFixtureBuilder;
-import org.apache.shardingsphere.infra.exception.generic.UnsupportedSQLOperationException;
import org.apache.shardingsphere.infra.rewrite.sql.token.common.pojo.SQLToken;
import org.apache.shardingsphere.infra.rewrite.sql.token.common.pojo.generic.SubstitutableColumnNameToken;
import org.junit.jupiter.api.BeforeEach;
@@ -29,7 +28,6 @@ import java.util.Collections;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class EncryptPredicateColumnTokenGeneratorTest {
@@ -54,10 +52,4 @@ class EncryptPredicateColumnTokenGeneratorTest {
assertThat(substitutableColumnNameTokens.size(), is(1));
assertThat(((SubstitutableColumnNameToken) substitutableColumnNameTokens.iterator().next()).toString(null), is("pwd_assist"));
}
-
- @Test
- void assertGenerateSQLTokensWhenJoinConditionUseDifferentEncryptor() {
- generator.setSchemas(Collections.emptyMap());
- assertThrows(UnsupportedSQLOperationException.class, () -> generator.generateSQLTokens(EncryptGeneratorFixtureBuilder.createSelectStatementContext()));
- }
}