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 51e91cc  add sql hint for write route only. (#13905)
51e91cc is described below

commit 51e91cc91b5e350502e0c7e2642100146f0f1edc
Author: tuichenchuxin <[email protected]>
AuthorDate: Fri Dec 3 16:58:20 2021 +0800

    add sql hint for write route only. (#13905)
    
    * add sql hint for write route only.
    
    * add sql hint for write route only.
    
    * add support for sql hint write route only
    
    * add support for sql hint write route only
    
    * add support for sql hint write route only
    
    * add support for write route only
---
 .../route/ReadwriteSplittingSQLRouter.java         |  4 +-
 .../impl/ReadwriteSplittingDataSourceRouter.java   | 17 ++--
 .../route/ReadwriteSplittingSQLRouterTest.java     | 19 ++++-
 .../statement/CommonSQLStatementContext.java       | 17 +++-
 .../infra/hint/SQLHintExtractor.java               | 94 ++++++++++++++++++++++
 .../infra/hint/SQLHintProperties.java              | 32 ++++++++
 .../infra/hint/SQLHintPropertiesKey.java           | 46 +++++++++++
 .../infra/hint}/SQLHintExtractorTest.java          | 17 ++--
 .../sql/common/extractor/SQLHintExtractor.java     | 70 ----------------
 9 files changed, 230 insertions(+), 86 deletions(-)

diff --git 
a/shardingsphere-features/shardingsphere-readwrite-splitting/shardingsphere-readwrite-splitting-core/src/main/java/org/apache/shardingsphere/readwritesplitting/route/ReadwriteSplittingSQLRouter.java
 
b/shardingsphere-features/shardingsphere-readwrite-splitting/shardingsphere-readwrite-splitting-core/src/main/java/org/apache/shardingsphere/readwritesplitting/route/ReadwriteSplittingSQLRouter.java
index 6bc0c4c..72e4436 100644
--- 
a/shardingsphere-features/shardingsphere-readwrite-splitting/shardingsphere-readwrite-splitting-core/src/main/java/org/apache/shardingsphere/readwritesplitting/route/ReadwriteSplittingSQLRouter.java
+++ 
b/shardingsphere-features/shardingsphere-readwrite-splitting/shardingsphere-readwrite-splitting-core/src/main/java/org/apache/shardingsphere/readwritesplitting/route/ReadwriteSplittingSQLRouter.java
@@ -43,7 +43,7 @@ public final class ReadwriteSplittingSQLRouter implements 
SQLRouter<ReadwriteSpl
     @Override
     public RouteContext createRouteContext(final LogicSQL logicSQL, final 
ShardingSphereMetaData metaData, final ReadwriteSplittingRule rule, final 
ConfigurationProperties props) {
         RouteContext result = new RouteContext();
-        String dataSourceName = new 
ReadwriteSplittingDataSourceRouter(rule.getSingleDataSourceRule()).route(logicSQL.getSqlStatementContext().getSqlStatement());
+        String dataSourceName = new 
ReadwriteSplittingDataSourceRouter(rule.getSingleDataSourceRule()).route(logicSQL.getSqlStatementContext());
         result.getRouteUnits().add(new RouteUnit(new 
RouteMapper(DefaultSchema.LOGIC_NAME, dataSourceName), 
Collections.emptyList()));
         return result;
     }
@@ -58,7 +58,7 @@ public final class ReadwriteSplittingSQLRouter implements 
SQLRouter<ReadwriteSpl
             Optional<ReadwriteSplittingDataSourceRule> dataSourceRule = 
rule.findDataSourceRule(dataSourceName);
             if (dataSourceRule.isPresent() && 
dataSourceRule.get().getName().equalsIgnoreCase(each.getDataSourceMapper().getActualName()))
 {
                 toBeRemoved.add(each);
-                String actualDataSourceName = new 
ReadwriteSplittingDataSourceRouter(dataSourceRule.get()).route(logicSQL.getSqlStatementContext().getSqlStatement());
+                String actualDataSourceName = new 
ReadwriteSplittingDataSourceRouter(dataSourceRule.get()).route(logicSQL.getSqlStatementContext());
                 toBeAdded.add(new RouteUnit(new 
RouteMapper(each.getDataSourceMapper().getLogicName(), actualDataSourceName), 
each.getTableMappers()));
             }
         }
diff --git 
a/shardingsphere-features/shardingsphere-readwrite-splitting/shardingsphere-readwrite-splitting-core/src/main/java/org/apache/shardingsphere/readwritesplitting/route/impl/ReadwriteSplittingDataSourceRouter.java
 
b/shardingsphere-features/shardingsphere-readwrite-splitting/shardingsphere-readwrite-splitting-core/src/main/java/org/apache/shardingsphere/readwritesplitting/route/impl/ReadwriteSplittingDataSourceRouter.java
index 7110ac9..b371123 100644
--- 
a/shardingsphere-features/shardingsphere-readwrite-splitting/shardingsphere-readwrite-splitting-core/src/main/java/org/apache/shardingsphere/readwritesplitting/route/impl/ReadwriteSplittingDataSourceRouter.java
+++ 
b/shardingsphere-features/shardingsphere-readwrite-splitting/shardingsphere-readwrite-splitting-core/src/main/java/org/apache/shardingsphere/readwritesplitting/route/impl/ReadwriteSplittingDataSourceRouter.java
@@ -21,6 +21,8 @@ import com.google.common.base.Strings;
 import lombok.RequiredArgsConstructor;
 import org.apache.shardingsphere.infra.aware.DataSourceNameAware;
 import org.apache.shardingsphere.infra.aware.DataSourceNameAwareFactory;
+import 
org.apache.shardingsphere.infra.binder.statement.CommonSQLStatementContext;
+import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
 import org.apache.shardingsphere.infra.hint.HintManager;
 import org.apache.shardingsphere.transaction.TransactionHolder;
 import 
org.apache.shardingsphere.readwritesplitting.rule.ReadwriteSplittingDataSourceRule;
@@ -43,11 +45,11 @@ public final class ReadwriteSplittingDataSourceRouter {
     /**
      * Route.
      * 
-     * @param sqlStatement SQL statement
+     * @param sqlStatementContext SQL statement context
      * @return data source name
      */
-    public String route(final SQLStatement sqlStatement) {
-        if (isPrimaryRoute(sqlStatement)) {
+    public String route(final SQLStatementContext<?> sqlStatementContext) {
+        if (isPrimaryRoute(sqlStatementContext)) {
             String autoAwareDataSourceName = rule.getAutoAwareDataSourceName();
             if (Strings.isNullOrEmpty(autoAwareDataSourceName)) {
                 return rule.getWriteDataSourceName();
@@ -69,8 +71,13 @@ public final class ReadwriteSplittingDataSourceRouter {
         return rule.getLoadBalancer().getDataSource(rule.getName(), 
rule.getWriteDataSourceName(), rule.getReadDataSourceNames());
     }
     
-    private boolean isPrimaryRoute(final SQLStatement sqlStatement) {
-        return containsLockSegment(sqlStatement) || !(sqlStatement instanceof 
SelectStatement) || HintManager.isWriteRouteOnly() || 
TransactionHolder.isTransaction();
+    private boolean isPrimaryRoute(final SQLStatementContext<?> 
sqlStatementContext) {
+        SQLStatement sqlStatement = sqlStatementContext.getSqlStatement();
+        return containsLockSegment(sqlStatement) || !(sqlStatement instanceof 
SelectStatement) || isHintWriteRouteOnly(sqlStatementContext) || 
TransactionHolder.isTransaction();
+    }
+    
+    private boolean isHintWriteRouteOnly(final SQLStatementContext<?> 
sqlStatementContext) {
+        return HintManager.isWriteRouteOnly() || (sqlStatementContext 
instanceof CommonSQLStatementContext && ((CommonSQLStatementContext<?>) 
sqlStatementContext).isHintWriteRouteOnly());
     }
     
     private boolean containsLockSegment(final SQLStatement sqlStatement) {
diff --git 
a/shardingsphere-features/shardingsphere-readwrite-splitting/shardingsphere-readwrite-splitting-core/src/test/java/org/apache/shardingsphere/readwritesplitting/route/ReadwriteSplittingSQLRouterTest.java
 
b/shardingsphere-features/shardingsphere-readwrite-splitting/shardingsphere-readwrite-splitting-core/src/test/java/org/apache/shardingsphere/readwritesplitting/route/ReadwriteSplittingSQLRouterTest.java
index b0621ee..43c0931 100644
--- 
a/shardingsphere-features/shardingsphere-readwrite-splitting/shardingsphere-readwrite-splitting-core/src/test/java/org/apache/shardingsphere/readwritesplitting/route/ReadwriteSplittingSQLRouterTest.java
+++ 
b/shardingsphere-features/shardingsphere-readwrite-splitting/shardingsphere-readwrite-splitting-core/src/test/java/org/apache/shardingsphere/readwritesplitting/route/ReadwriteSplittingSQLRouterTest.java
@@ -18,7 +18,9 @@
 package org.apache.shardingsphere.readwritesplitting.route;
 
 import org.apache.shardingsphere.infra.binder.LogicSQL;
+import 
org.apache.shardingsphere.infra.binder.statement.CommonSQLStatementContext;
 import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
+import 
org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementContext;
 import 
org.apache.shardingsphere.infra.config.properties.ConfigurationProperties;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 import 
org.apache.shardingsphere.infra.metadata.resource.ShardingSphereResource;
@@ -36,6 +38,7 @@ import 
org.apache.shardingsphere.spi.ordered.OrderedSPIRegistry;
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.LockSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.InsertStatement;
+import 
org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLInsertStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLSelectStatement;
 import org.junit.Before;
@@ -69,7 +72,7 @@ public final class ReadwriteSplittingSQLRouterTest {
     private ReadwriteSplittingRule rule;
     
     @Mock
-    private SQLStatementContext<SQLStatement> sqlStatementContext;
+    private CommonSQLStatementContext<SQLStatement> sqlStatementContext;
     
     private ReadwriteSplittingSQLRouter sqlRouter;
     
@@ -192,6 +195,20 @@ public final class ReadwriteSplittingSQLRouterTest {
         assertThat(routedDataSourceNames.next(), is(READ_DATASOURCE));
     }
     
+    @Test
+    public void assertSqlHintRouteWriteOnly() {
+        SelectStatement statement = mock(SelectStatement.class);
+        CommonSQLStatementContext<SelectStatement> sqlStatementContext = 
mock(SelectStatementContext.class);
+        when(sqlStatementContext.getSqlStatement()).thenReturn(statement);
+        when(sqlStatementContext.isHintWriteRouteOnly()).thenReturn(true);
+        LogicSQL logicSQL = new LogicSQL(sqlStatementContext, "", 
Collections.emptyList());
+        ShardingSphereRuleMetaData ruleMetaData = new 
ShardingSphereRuleMetaData(Collections.emptyList(), 
Collections.singleton(rule));
+        ShardingSphereMetaData metaData = new 
ShardingSphereMetaData("logic_schema", mock(ShardingSphereResource.class, 
RETURNS_DEEP_STUBS), ruleMetaData, mock(ShardingSphereSchema.class));
+        RouteContext actual = sqlRouter.createRouteContext(logicSQL, metaData, 
rule, new ConfigurationProperties(new Properties()));
+        Iterator<String> routedDataSourceNames = 
actual.getActualDataSourceNames().iterator();
+        assertThat(routedDataSourceNames.next(), is(WRITE_DATASOURCE));
+    }
+    
     private RouteContext mockRouteContext() {
         RouteContext result = new RouteContext();
         RouteUnit routeUnit = new RouteUnit(new RouteMapper(DATASOURCE_NAME, 
DATASOURCE_NAME), Collections.singletonList(new RouteMapper("table", 
"table_0")));
diff --git 
a/shardingsphere-infra/shardingsphere-infra-binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/CommonSQLStatementContext.java
 
b/shardingsphere-infra/shardingsphere-infra-binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/CommonSQLStatementContext.java
index 30ae5ac..1d2d0e0 100644
--- 
a/shardingsphere-infra/shardingsphere-infra-binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/CommonSQLStatementContext.java
+++ 
b/shardingsphere-infra/shardingsphere-infra-binder/src/main/java/org/apache/shardingsphere/infra/binder/statement/CommonSQLStatementContext.java
@@ -21,8 +21,7 @@ import lombok.Getter;
 import org.apache.shardingsphere.infra.binder.segment.table.TablesContext;
 import org.apache.shardingsphere.infra.database.type.DatabaseType;
 import org.apache.shardingsphere.infra.database.type.DatabaseTypeRegistry;
-import 
org.apache.shardingsphere.sql.parser.sql.common.extractor.SQLHintExtractor;
-import 
org.apache.shardingsphere.sql.parser.sql.common.statement.AbstractSQLStatement;
+import org.apache.shardingsphere.infra.hint.SQLHintExtractor;
 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.MySQLStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.opengauss.OpenGaussStatement;
@@ -48,10 +47,13 @@ public class CommonSQLStatementContext<T extends 
SQLStatement> implements SQLSta
     
     private final DatabaseType databaseType;
     
+    private final SQLHintExtractor sqlHintExtractor;
+    
     public CommonSQLStatementContext(final T sqlStatement) {
         this.sqlStatement = sqlStatement;
         tablesContext = new TablesContext(Collections.emptyList());
         databaseType = getDatabaseType(sqlStatement);
+        sqlHintExtractor = new SQLHintExtractor(sqlStatement);
     }
     
     private DatabaseType getDatabaseType(final SQLStatement sqlStatement) {
@@ -82,6 +84,15 @@ public class CommonSQLStatementContext<T extends 
SQLStatement> implements SQLSta
      * @return dataSource name
      */
     public Optional<String> findHintDataSourceName() {
-        return SQLHintExtractor.findHintDataSourceName((AbstractSQLStatement) 
sqlStatement);
+        return sqlHintExtractor.findHintDataSourceName();
+    }
+    
+    /**
+     * Judge whether is hint routed to write data source or not.
+     *
+     * @return whether is hint routed to write data source or not
+     */
+    public boolean isHintWriteRouteOnly() {
+        return sqlHintExtractor.isHintWriteRouteOnly();
     }
 }
diff --git 
a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/hint/SQLHintExtractor.java
 
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/hint/SQLHintExtractor.java
new file mode 100644
index 0000000..05f1406
--- /dev/null
+++ 
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/hint/SQLHintExtractor.java
@@ -0,0 +1,94 @@
+/*
+ * 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.infra.hint;
+
+import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.CommentSegment;
+import 
org.apache.shardingsphere.sql.parser.sql.common.statement.AbstractSQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+
+import java.util.Optional;
+import java.util.Properties;
+
+/**
+ * SQL hint extractor.
+ */
+public final class SQLHintExtractor {
+    
+    private static final String SQL_COMMENT_SUFFIX = "*/";
+    
+    private static final String SQL_HINT_TOKEN = "shardingsphere hint:";
+    
+    private static final String SQL_HINT_SPLIT = "=";
+    
+    private final SQLHintProperties sqlHintProperties;
+    
+    public SQLHintExtractor(final SQLStatement sqlStatement) {
+        sqlHintProperties = sqlStatement instanceof AbstractSQLStatement ? 
extract((AbstractSQLStatement) sqlStatement) : new SQLHintProperties(new 
Properties());
+    }
+    
+    /**
+     * Extract from statement.
+     *
+     * @param statement statement
+     * @return sql hint properties
+     */
+    public SQLHintProperties extract(final AbstractSQLStatement statement) {
+        Properties properties = new Properties();
+        for (CommentSegment each : statement.getCommentSegments()) {
+            appendHintProperties(each.getText(), properties);
+        }
+        return new SQLHintProperties(properties);
+    }
+    
+    private void appendHintProperties(final String comment, final Properties 
properties) {
+        int startIndex = comment.toLowerCase().indexOf(SQL_HINT_TOKEN);
+        if (startIndex < 0) {
+            return;
+        }
+        startIndex = startIndex + SQL_HINT_TOKEN.length();
+        int endIndex = comment.endsWith(SQL_COMMENT_SUFFIX) ? 
comment.indexOf(SQL_COMMENT_SUFFIX) : comment.length();
+        String[] hintValue = comment.substring(startIndex, 
endIndex).trim().split(SQL_HINT_SPLIT);
+        if (2 == hintValue.length && hintValue[0].trim().length() > 0 && 
hintValue[1].trim().length() > 0) {
+            if 
(SQLHintPropertiesKey.DATASOURCE_NAME_KEY.getKey().equalsIgnoreCase(hintValue[0].trim()))
 {
+                
properties.setProperty(SQLHintPropertiesKey.DATASOURCE_NAME_KEY.getKey(), 
hintValue[1].trim());
+            }
+            if 
(SQLHintPropertiesKey.WRITE_ROUTE_ONLY_KEY.getKey().equalsIgnoreCase(hintValue[0].trim()))
 {
+                
properties.setProperty(SQLHintPropertiesKey.WRITE_ROUTE_ONLY_KEY.getKey(), 
hintValue[1].trim());
+            }
+        }
+    }
+    
+    /**
+     * Find hint data source name.
+     *
+     * @return data source name
+     */
+    public Optional<String> findHintDataSourceName() {
+        String result = 
sqlHintProperties.getValue(SQLHintPropertiesKey.DATASOURCE_NAME_KEY);
+        return result.isEmpty() ? Optional.empty() : Optional.of(result);
+    }
+    
+    /**
+     * Judge whether is hint routed to write data source or not.
+     *
+     * @return whether is hint routed to write data source or not
+     */
+    public boolean isHintWriteRouteOnly() {
+        return 
sqlHintProperties.getValue(SQLHintPropertiesKey.WRITE_ROUTE_ONLY_KEY);
+    }
+}
diff --git 
a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/hint/SQLHintProperties.java
 
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/hint/SQLHintProperties.java
new file mode 100644
index 0000000..fb2dac0
--- /dev/null
+++ 
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/hint/SQLHintProperties.java
@@ -0,0 +1,32 @@
+/*
+ * 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.infra.hint;
+
+import org.apache.shardingsphere.infra.properties.TypedProperties;
+
+import java.util.Properties;
+
+/**
+ * SQL Hint properties.
+ */
+public final class SQLHintProperties extends 
TypedProperties<SQLHintPropertiesKey> {
+    
+    public SQLHintProperties(final Properties props) {
+        super(SQLHintPropertiesKey.class, props);
+    }
+}
diff --git 
a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/hint/SQLHintPropertiesKey.java
 
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/hint/SQLHintPropertiesKey.java
new file mode 100644
index 0000000..3b3fe25
--- /dev/null
+++ 
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/hint/SQLHintPropertiesKey.java
@@ -0,0 +1,46 @@
+/*
+ * 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.infra.hint;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.infra.properties.TypedPropertyKey;
+
+/**
+ * Typed property key of SQL Hint.
+ */
+@Getter
+@RequiredArgsConstructor
+public enum SQLHintPropertiesKey implements TypedPropertyKey {
+    
+    /**
+     * Hint data source name.
+     */
+    DATASOURCE_NAME_KEY("dataSourceName", "", String.class),
+    
+    /**
+     * Whether hint route write data source or not.
+     */
+    WRITE_ROUTE_ONLY_KEY("writeRouteOnly", String.valueOf(Boolean.FALSE), 
boolean.class);
+    
+    private final String key;
+    
+    private final String defaultValue;
+    
+    private final Class<?> type;
+}
diff --git 
a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/common/extractor/SQLHintExtractorTest.java
 
b/shardingsphere-infra/shardingsphere-infra-common/src/test/java/org/apache/shardingsphere/infra/hint/SQLHintExtractorTest.java
similarity index 72%
rename from 
shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/common/extractor/SQLHintExtractorTest.java
rename to 
shardingsphere-infra/shardingsphere-infra-common/src/test/java/org/apache/shardingsphere/infra/hint/SQLHintExtractorTest.java
index 3c9fb35..b1ec3a3 100644
--- 
a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/common/extractor/SQLHintExtractorTest.java
+++ 
b/shardingsphere-infra/shardingsphere-infra-common/src/test/java/org/apache/shardingsphere/infra/hint/SQLHintExtractorTest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.sql.parser.sql.common.extractor;
+package org.apache.shardingsphere.infra.hint;
 
 import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.CommentSegment;
 import 
org.apache.shardingsphere.sql.parser.sql.common.statement.AbstractSQLStatement;
@@ -36,24 +36,31 @@ public final class SQLHintExtractorTest {
     @Test
     public void assertFindHintDataSourceNameExist() {
         AbstractSQLStatement statement = mock(AbstractSQLStatement.class);
-        
when(statement.getCommentSegments()).thenReturn(Collections.singletonList(new 
CommentSegment("/* sql hint: datasourceName=ds_1 */", 0, 0)));
-        Optional<String> dataSourceName = 
SQLHintExtractor.findHintDataSourceName(statement);
+        
when(statement.getCommentSegments()).thenReturn(Collections.singletonList(new 
CommentSegment("/* ShardingSphere hint: dataSourceName=ds_1 */", 0, 0)));
+        Optional<String> dataSourceName = new 
SQLHintExtractor(statement).findHintDataSourceName();
         assertTrue(dataSourceName.isPresent());
         assertThat(dataSourceName.get(), is("ds_1"));
     }
     
     @Test
+    public void assertSQLHintWriteRouteOnly() {
+        AbstractSQLStatement statement = mock(AbstractSQLStatement.class);
+        
when(statement.getCommentSegments()).thenReturn(Collections.singletonList(new 
CommentSegment("/* ShardingSphere hint: writeRouteOnly=true */", 0, 0)));
+        assertTrue(new SQLHintExtractor(statement).isHintWriteRouteOnly());
+    }
+    
+    @Test
     public void assertFindHintDataSourceNameNotExist() {
         AbstractSQLStatement statement = mock(AbstractSQLStatement.class);
         
when(statement.getCommentSegments()).thenReturn(Collections.singletonList(new 
CommentSegment("/* no hint */", 0, 0)));
-        Optional<String> dataSourceName = 
SQLHintExtractor.findHintDataSourceName(statement);
+        Optional<String> dataSourceName = new 
SQLHintExtractor(statement).findHintDataSourceName();
         assertFalse(dataSourceName.isPresent());
     }
     
     @Test
     public void assertFindHintDataSourceNameNotExistWithoutComment() {
         AbstractSQLStatement statement = mock(AbstractSQLStatement.class);
-        Optional<String> dataSourceName = 
SQLHintExtractor.findHintDataSourceName(statement);
+        Optional<String> dataSourceName = new 
SQLHintExtractor(statement).findHintDataSourceName();
         assertFalse(dataSourceName.isPresent());
     }
 }
diff --git 
a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/extractor/SQLHintExtractor.java
 
b/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/extractor/SQLHintExtractor.java
deleted file mode 100644
index 7388cb3..0000000
--- 
a/shardingsphere-sql-parser/shardingsphere-sql-parser-statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/extractor/SQLHintExtractor.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.sql.common.extractor;
-
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
-import 
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.CommentSegment;
-import 
org.apache.shardingsphere.sql.parser.sql.common.statement.AbstractSQLStatement;
-
-import java.util.Optional;
-
-/**
- * SQL hint extractor.
- */
-@NoArgsConstructor(access = AccessLevel.PRIVATE)
-public final class SQLHintExtractor {
-    
-    private static final String SQL_COMMENT_SUFFIX = "*/";
-    
-    private static final String SQL_HINT_TOKEN = "sql hint:";
-    
-    private static final String SQL_HINT_SPLIT = "=";
-    
-    private static final String SQL_HINT_DATASOURCE_NAME_KEY = 
"datasourcename";
-    
-    /**
-     * Find hint data source name.
-     *
-     * @param statement statement
-     * @return data source name
-     */
-    public static Optional<String> findHintDataSourceName(final 
AbstractSQLStatement statement) {
-        for (CommentSegment each : statement.getCommentSegments()) {
-            Optional<String> result = 
findDataSourceNameFromComment(each.getText());
-            if (result.isPresent()) {
-                return result;
-            }
-        }
-        return Optional.empty();
-    }
-    
-    private static Optional<String> findDataSourceNameFromComment(final String 
comment) {
-        int startIndex = comment.toLowerCase().indexOf(SQL_HINT_TOKEN);
-        if (startIndex < 0) {
-            return Optional.empty();
-        }
-        startIndex = startIndex + SQL_HINT_TOKEN.length();
-        int endIndex = comment.endsWith(SQL_COMMENT_SUFFIX) ? 
comment.indexOf(SQL_COMMENT_SUFFIX) : comment.length();
-        String[] hintValue = comment.substring(startIndex, 
endIndex).trim().split(SQL_HINT_SPLIT);
-        if (2 == hintValue.length && 
SQL_HINT_DATASOURCE_NAME_KEY.equalsIgnoreCase(hintValue[0].trim()) && 
hintValue[1].trim().length() > 0) {
-            return Optional.of(hintValue[1].trim());
-        }
-        return Optional.empty();
-    }
-}

Reply via email to