This is an automated email from the ASF dual-hosted git repository.

duanzhengqiang 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 b2fad36a125 add create view validator (#18006)
b2fad36a125 is described below

commit b2fad36a125897fc3af1a774a0e1390c9a5db2a1
Author: Chuxin Chen <[email protected]>
AuthorDate: Mon May 30 16:38:53 2022 +0800

    add create view validator (#18006)
    
    * add create view validator
    
    * Add create view statement validator.
    
    * add validator for create view in sharding
---
 .../impl/ShardingCreateViewStatementValidator.java | 71 ++++++++++++++++++-
 .../ShardingCreateViewStatementValidatorTest.java  | 79 +++++++++++++++-------
 2 files changed, 125 insertions(+), 25 deletions(-)

diff --git 
a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/impl/ShardingCreateViewStatementValidator.java
 
b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/impl/ShardingCreateViewStatementValidator.java
index e31b6776690..e3513c08b1f 100644
--- 
a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/impl/ShardingCreateViewStatementValidator.java
+++ 
b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/main/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/impl/ShardingCreateViewStatementValidator.java
@@ -19,13 +19,23 @@ package 
org.apache.shardingsphere.sharding.route.engine.validator.ddl.impl;
 
 import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
+import org.apache.shardingsphere.infra.exception.ShardingSphereException;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import org.apache.shardingsphere.infra.route.context.RouteContext;
 import 
org.apache.shardingsphere.sharding.route.engine.validator.ddl.ShardingDDLStatementValidator;
 import org.apache.shardingsphere.sharding.rule.ShardingRule;
+import 
org.apache.shardingsphere.sql.parser.sql.common.extractor.TableExtractor;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.AggregationProjectionSegment;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.CreateViewStatement;
+import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
+import 
org.apache.shardingsphere.sql.parser.sql.dialect.handler.dml.SelectStatementHandler;
 
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
+import java.util.Optional;
 
 /**
  * Sharding create view statement validator.
@@ -35,11 +45,70 @@ public final class ShardingCreateViewStatementValidator 
extends ShardingDDLState
     @Override
     public void preValidate(final ShardingRule shardingRule, final 
SQLStatementContext<CreateViewStatement> sqlStatementContext,
                             final List<Object> parameters, final 
ShardingSphereDatabase database) {
-        // TODO prevent if has need merge select.
+        Optional<SelectStatement> selectStatement = 
sqlStatementContext.getSqlStatement().getSelect();
+        if (!selectStatement.isPresent()) {
+            return;
+        }
+        if (isShardingTablesWithoutBinding(shardingRule, sqlStatementContext, 
selectStatement.get())) {
+            throw new ShardingSphereException("View name has to bind to 
sharding tables!");
+        }
     }
     
     @Override
     public void postValidate(final ShardingRule shardingRule, final 
SQLStatementContext<CreateViewStatement> sqlStatementContext, final 
List<Object> parameters,
                              final ShardingSphereDatabase database, final 
ConfigurationProperties props, final RouteContext routeContext) {
+        Optional<SelectStatement> selectStatement = 
sqlStatementContext.getSqlStatement().getSelect();
+        if (!selectStatement.isPresent()) {
+            return;
+        }
+        if (isContainsNotSupportedViewStatement(selectStatement.get(), 
routeContext)) {
+            throw new ShardingSphereException("This view statement contains 
not supported query statement!");
+        }
+    }
+    
+    private boolean isShardingTablesWithoutBinding(final ShardingRule 
shardingRule, final SQLStatementContext<CreateViewStatement> 
sqlStatementContext, final SelectStatement selectStatement) {
+        TableExtractor extractor = new TableExtractor();
+        extractor.extractTablesFromSelect(selectStatement);
+        Collection<SimpleTableSegment> tableSegments = 
extractor.getRewriteTables();
+        for (SimpleTableSegment each : tableSegments) {
+            String logicTable = each.getTableName().getIdentifier().getValue();
+            if (shardingRule.isShardingTable(logicTable) && 
!isBindingTables(shardingRule, 
sqlStatementContext.getSqlStatement().getView().getTableName().getIdentifier().getValue(),
 logicTable)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    private boolean isBindingTables(final ShardingRule shardingRule, final 
String logicViewName, final String logicTable) {
+        Collection<String> bindTables = Arrays.asList(logicTable, 
logicViewName);
+        return shardingRule.isAllBindingTables(bindTables);
+    }
+    
+    private boolean isContainsNotSupportedViewStatement(final SelectStatement 
selectStatement, final RouteContext routeContext) {
+        if (routeContext.getRouteUnits().size() <= 1) {
+            return false;
+        }
+        return hasGroupBy(selectStatement) || hasAggregation(selectStatement) 
|| hasDistinct(selectStatement) || hasLimit(selectStatement);
+    }
+    
+    private boolean hasGroupBy(final SelectStatement selectStatement) {
+        return selectStatement.getGroupBy().map(groupBySegment -> 
!groupBySegment.getGroupByItems().isEmpty()).orElse(false);
+    }
+    
+    private boolean hasAggregation(final SelectStatement selectStatement) {
+        for (ProjectionSegment each : 
selectStatement.getProjections().getProjections()) {
+            if (each instanceof AggregationProjectionSegment) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    private boolean hasDistinct(final SelectStatement selectStatement) {
+        return selectStatement.getProjections().isDistinctRow();
+    }
+    
+    private boolean hasLimit(final SelectStatement selectStatement) {
+        return 
SelectStatementHandler.getLimitSegment(selectStatement).isPresent();
     }
 }
diff --git 
a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/test/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/ShardingCreateViewStatementValidatorTest.java
 
b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/test/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/ShardingCreateViewStatementValidatorTest.java
index c51740bc182..a8d935924dc 100644
--- 
a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/test/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/ShardingCreateViewStatementValidatorTest.java
+++ 
b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/test/java/org/apache/shardingsphere/sharding/route/engine/validator/ddl/ShardingCreateViewStatementValidatorTest.java
@@ -17,57 +17,88 @@
 
 package org.apache.shardingsphere.sharding.route.engine.validator.ddl;
 
-import 
org.apache.shardingsphere.infra.binder.statement.CommonSQLStatementContext;
-import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
+import 
org.apache.shardingsphere.infra.binder.statement.ddl.CreateViewStatementContext;
+import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
 import org.apache.shardingsphere.infra.exception.ShardingSphereException;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.route.context.RouteContext;
 import 
org.apache.shardingsphere.sharding.route.engine.validator.ddl.impl.ShardingCreateViewStatementValidator;
 import org.apache.shardingsphere.sharding.rule.ShardingRule;
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionsSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.TableNameSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.CreateViewStatement;
+import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.common.value.identifier.IdentifierValue;
-import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.ddl.MySQLCreateViewStatement;
-import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLSelectStatement;
-import org.junit.Ignore;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.Collections;
+import java.util.Optional;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-// TODO refactor after create view statement validator is completed.
-@Ignore
 @RunWith(MockitoJUnitRunner.class)
 public final class ShardingCreateViewStatementValidatorTest {
     
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private RouteContext routeContext;
+    
     @Mock
     private ShardingRule shardingRule;
     
+    @Mock
+    private CreateViewStatementContext createViewStatementContext;
+    
+    @Mock
+    private CreateViewStatement createViewStatement;
+    
+    @Mock
+    private SelectStatement selectStatement;
+    
+    @Before
+    public void setUp() {
+        
when(createViewStatementContext.getSqlStatement()).thenReturn(createViewStatement);
+        
when(createViewStatement.getSelect()).thenReturn(Optional.of(selectStatement));
+        when(selectStatement.getFrom()).thenReturn(new SimpleTableSegment(new 
TableNameSegment(0, 0, new IdentifierValue("t_order"))));
+        when(createViewStatement.getView()).thenReturn(new 
SimpleTableSegment(new TableNameSegment(0, 0, new 
IdentifierValue("order_view"))));
+        when(routeContext.getRouteUnits().size()).thenReturn(2);
+    }
+    
+    @Test
+    public void assertPreValidateCreateView() {
+        when(shardingRule.isShardingTable(any())).thenReturn(true);
+        when(shardingRule.isAllBindingTables(any())).thenReturn(true);
+        new ShardingCreateViewStatementValidator().preValidate(shardingRule, 
createViewStatementContext, Collections.emptyList(), 
mock(ShardingSphereDatabase.class));
+    }
+    
+    @Test(expected = ShardingSphereException.class)
+    public void assertPreValidateCreateViewWithException() {
+        when(shardingRule.isShardingTable(any())).thenReturn(true);
+        when(shardingRule.isAllBindingTables(any())).thenReturn(false);
+        new ShardingCreateViewStatementValidator().preValidate(shardingRule, 
createViewStatementContext, Collections.emptyList(), 
mock(ShardingSphereDatabase.class));
+    }
+    
     @Test
-    public void assertPreValidateCreateViewForMySQL() {
-        MySQLSelectStatement selectStatement = new MySQLSelectStatement();
-        selectStatement.setFrom(new SimpleTableSegment(new TableNameSegment(0, 
0, new IdentifierValue("t_order"))));
-        MySQLCreateViewStatement sqlStatement = new MySQLCreateViewStatement();
-        sqlStatement.setSelect(selectStatement);
-        SQLStatementContext<CreateViewStatement> sqlStatementContext = new 
CommonSQLStatementContext<>(sqlStatement);
-        when(shardingRule.isShardingTable("t_order")).thenReturn(false);
-        new ShardingCreateViewStatementValidator().preValidate(shardingRule, 
sqlStatementContext, Collections.emptyList(), 
mock(ShardingSphereDatabase.class));
+    public void assertPostValidateCreateView() {
+        ProjectionsSegment projectionsSegment = mock(ProjectionsSegment.class);
+        when(selectStatement.getProjections()).thenReturn(projectionsSegment);
+        new ShardingCreateViewStatementValidator().postValidate(shardingRule, 
createViewStatementContext, Collections.emptyList(), 
mock(ShardingSphereDatabase.class),
+                mock(ConfigurationProperties.class), routeContext);
     }
     
     @Test(expected = ShardingSphereException.class)
-    public void assertPreValidateCreateViewWithShardingTableForMySQL() {
-        MySQLSelectStatement selectStatement = new MySQLSelectStatement();
-        selectStatement.setFrom(new SimpleTableSegment(new TableNameSegment(0, 
0, new IdentifierValue("t_order"))));
-        MySQLCreateViewStatement sqlStatement = new MySQLCreateViewStatement();
-        sqlStatement.setSelect(selectStatement);
-        ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
-        SQLStatementContext<CreateViewStatement> sqlStatementContext = new 
CommonSQLStatementContext<>(sqlStatement);
-        when(shardingRule.isShardingTable("t_order")).thenReturn(true);
-        new ShardingCreateViewStatementValidator().preValidate(shardingRule, 
sqlStatementContext, Collections.emptyList(), database);
+    public void assertPostValidateCreateViewWithException() {
+        ProjectionsSegment projectionsSegment = mock(ProjectionsSegment.class);
+        when(projectionsSegment.isDistinctRow()).thenReturn(true);
+        when(selectStatement.getProjections()).thenReturn(projectionsSegment);
+        new ShardingCreateViewStatementValidator().postValidate(shardingRule, 
createViewStatementContext, Collections.emptyList(), 
mock(ShardingSphereDatabase.class),
+                mock(ConfigurationProperties.class), routeContext);
     }
 }

Reply via email to