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 2023/03/19 16:42:57 UTC

[shardingsphere] branch master updated: Proxy For HBase add Check SQL (#24645)

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

zhangliang 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 78bb2e143b7  Proxy For HBase add Check SQL (#24645)
78bb2e143b7 is described below

commit 78bb2e143b701ed9261388ed9629189e72aa8772
Author: galaxy <ga...@tencent.com>
AuthorDate: Mon Mar 20 00:42:46 2023 +0800

     Proxy For HBase add Check SQL (#24645)
    
    * Support netty parameter ChannelOption.SO_BACKLOG configurable (#17812)
    
    * Proxy For HBase add Check SQL
---
 .../CommonHeterogeneousSQLStatementChecker.java    |  94 ++++++++
 .../backend/hbase/checker/HBaseCheckerFactory.java |  53 +++++
 .../HeterogeneousDeleteStatementChecker.java       |  43 ++++
 .../HeterogeneousInsertStatementChecker.java       |  69 ++++++
 .../HeterogeneousSQLStatementChecker.java}         |  26 +--
 .../HeterogeneousSelectStatementChecker.java       | 130 +++++++++++
 .../HeterogeneousUpdateStatementChecker.java       |  56 +++++
 .../handler/ErrorHintCommentQueryHandler.java      |  72 ++++++
 .../hbase/handler/HBaseBackendQueryHandler.java    |  64 +++++
 ...QueryCallback.java => HBaseBackendHandler.java} |  23 +-
 .../backend/hbase/result/HBaseQueryCallback.java   |   1 -
 .../hbase/result/query/HBaseDescribeResultSet.java |   3 +-
 .../hbase/result/query/HBaseQueryFactory.java      |  44 ++++
 .../hbase/result/update/HBaseDeleteUpdater.java    |   1 -
 .../hbase/result/update/HBaseUpdateFactory.java    |  44 ++++
 ...CommonHeterogeneousSQLStatementCheckerTest.java | 136 +++++++++++
 .../checker/HBaseDatabaseCheckerFactoryTest.java   |  73 ++++++
 .../HeterogeneousDeleteStatementCheckerTest.java   |  97 ++++++++
 .../HeterogeneousInsertStatementCheckerTest.java   | 105 +++++++++
 .../HeterogeneousSelectStatementCheckerTest.java   | 259 +++++++++++++++++++++
 .../HeterogeneousUpdateStatementCheckerTest.java   | 107 +++++++++
 21 files changed, 1472 insertions(+), 28 deletions(-)

diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/CommonHeterogeneousSQLStatementChecker.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/CommonHeterogeneousSQLStatementChecker.java
new file mode 100644
index 00000000000..26e801d96ef
--- /dev/null
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/CommonHeterogeneousSQLStatementChecker.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.proxy.backend.hbase.checker;
+
+import com.google.common.base.Preconditions;
+import lombok.Getter;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BinaryOperationExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.InExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ListExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.LiteralExpressionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.WhereSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Abstract checker.
+ * 
+ * @param <T> SQLStatement.
+ */
+@Getter
+public class CommonHeterogeneousSQLStatementChecker<T extends SQLStatement> implements HeterogeneousSQLStatementChecker<T> {
+    
+    protected static final List<String> ALLOW_KEYS = Arrays.asList("rowKey", "row_key", "key", "pk", "id");
+    
+    private final T sqlStatement;
+    
+    public CommonHeterogeneousSQLStatementChecker(final T sqlStatement) {
+        this.sqlStatement = sqlStatement;
+    }
+    
+    @Override
+    public void execute() {
+        
+    }
+    
+    protected void checkIsSinglePointQuery(final Optional<WhereSegment> whereSegment) {
+        Preconditions.checkArgument(whereSegment.isPresent(), "Must Have Where Segment");
+        ExpressionSegment whereExpr = whereSegment.get().getExpr();
+        Preconditions.checkArgument(whereExpr instanceof BinaryOperationExpression, "Only Support BinaryOperationExpression");
+        BinaryOperationExpression expression = (BinaryOperationExpression) whereExpr;
+        Preconditions.checkArgument(!(expression.getLeft() instanceof BinaryOperationExpression), "Do not supported Multiple expressions");
+        Preconditions.checkArgument(expression.getLeft() instanceof ColumnSegment, "left segment must is ColumnSegment");
+        Preconditions.checkArgument(expression.getOperator().equals("="), "Only Supported `=` operator");
+        String rowKey = ((ColumnSegment) expression.getLeft()).getIdentifier().getValue();
+        boolean isAllowKey = ALLOW_KEYS.stream().anyMatch(each -> each.equalsIgnoreCase(rowKey));
+        Preconditions.checkArgument(isAllowKey, String.format("%s is not a allowed key", rowKey));
+    }
+    
+    /**
+     * Check value is literal or parameter marker.
+     * 
+     * @param expressionSegment value segment
+     * 
+     * @return is supported
+     */
+    protected boolean isAllowExpressionSegment(final ExpressionSegment expressionSegment) {
+        return expressionSegment instanceof LiteralExpressionSegment || expressionSegment instanceof ParameterMarkerExpressionSegment;
+    }
+    
+    /**
+     * Check in expression.
+     *
+     * @param whereExpr InExpression
+     */
+    protected void checkInExpressionIsExpected(final ExpressionSegment whereExpr) {
+        InExpression expression = (InExpression) whereExpr;
+        Preconditions.checkArgument(expression.getLeft() instanceof ColumnSegment, "left segment must is ColumnSegment");
+        String rowKey = ((ColumnSegment) expression.getLeft()).getIdentifier().getValue();
+        boolean isAllowKey = ALLOW_KEYS.stream().anyMatch(each -> each.equalsIgnoreCase(rowKey));
+        Preconditions.checkArgument(isAllowKey, String.format("%s is not a allowed key", rowKey));
+        Preconditions.checkArgument(!expression.isNot(), "Do not supported `not in`");
+        Preconditions.checkArgument(expression.getRight() instanceof ListExpression, "Only supported ListExpression");
+    }
+}
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HBaseCheckerFactory.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HBaseCheckerFactory.java
new file mode 100644
index 00000000000..0a295e63e5f
--- /dev/null
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HBaseCheckerFactory.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.proxy.backend.hbase.checker;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.DeleteStatement;
+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.common.statement.dml.UpdateStatement;
+
+/**
+ * HBase checker factory.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class HBaseCheckerFactory {
+    
+    /**
+     * Create new instance of heterogeneous database checker.
+     *
+     * @param sqlStatement sql statement
+     * @return instance of database backend handler
+     */
+    public static HeterogeneousSQLStatementChecker<?> newInstance(final SQLStatement sqlStatement) {
+        if (sqlStatement instanceof SelectStatement) {
+            return new HeterogeneousSelectStatementChecker((SelectStatement) sqlStatement);
+        } else if (sqlStatement instanceof InsertStatement) {
+            return new HeterogeneousInsertStatementChecker((InsertStatement) sqlStatement);
+        } else if (sqlStatement instanceof DeleteStatement) {
+            return new HeterogeneousDeleteStatementChecker((DeleteStatement) sqlStatement);
+        } else if (sqlStatement instanceof UpdateStatement) {
+            return new HeterogeneousUpdateStatementChecker((UpdateStatement) sqlStatement);
+        } else {
+            return new CommonHeterogeneousSQLStatementChecker<>(sqlStatement);
+        }
+    }
+}
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousDeleteStatementChecker.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousDeleteStatementChecker.java
new file mode 100644
index 00000000000..47fc493f355
--- /dev/null
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousDeleteStatementChecker.java
@@ -0,0 +1,43 @@
+/*
+ * 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.proxy.backend.hbase.checker;
+
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.InExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.WhereSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.DeleteStatement;
+import java.util.Optional;
+
+/**
+ * Checker for delete statement.
+ */
+public class HeterogeneousDeleteStatementChecker extends CommonHeterogeneousSQLStatementChecker<DeleteStatement> {
+    
+    public HeterogeneousDeleteStatementChecker(final DeleteStatement sqlStatement) {
+        super(sqlStatement);
+    }
+    
+    @Override
+    public void execute() {
+        Optional<WhereSegment> whereSegment = getSqlStatement().getWhere();
+        if (whereSegment.isPresent() && whereSegment.get().getExpr() instanceof InExpression) {
+            checkInExpressionIsExpected(whereSegment.get().getExpr());
+        } else {
+            checkIsSinglePointQuery(whereSegment);
+        }
+    }
+}
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousInsertStatementChecker.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousInsertStatementChecker.java
new file mode 100644
index 00000000000..a89f56a3ac2
--- /dev/null
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousInsertStatementChecker.java
@@ -0,0 +1,69 @@
+/*
+ * 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.proxy.backend.hbase.checker;
+
+import com.google.common.base.Preconditions;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.InsertValuesSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.InsertStatement;
+import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLInsertStatement;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Checker for insert statement.
+ */
+public class HeterogeneousInsertStatementChecker extends CommonHeterogeneousSQLStatementChecker<InsertStatement> {
+    
+    public HeterogeneousInsertStatementChecker(final InsertStatement sqlStatement) {
+        super(sqlStatement);
+    }
+    
+    @Override
+    public void execute() {
+        checkIsExistsRowKeyInInsertColumns();
+        checkIsExistsSubQuery();
+        checkValueIsExpected();
+        checkOnDuplicateKey();
+    }
+    
+    private void checkIsExistsRowKeyInInsertColumns() {
+        List<String> columns = getSqlStatement().getColumns().stream().map(each -> each.getIdentifier().getValue()).collect(Collectors.toList());
+        Preconditions.checkArgument(!columns.isEmpty(), "The inserted column must be explicitly specified");
+        Preconditions.checkArgument(ALLOW_KEYS.stream().anyMatch(each -> each.equalsIgnoreCase(columns.get(0))), "First column must be rowKey");
+        boolean isExists = columns.subList(1, columns.size()).stream().anyMatch(ALLOW_KEYS::contains);
+        Preconditions.checkArgument(!isExists, "Cannot contain multiple rowKey");
+    }
+    
+    private void checkIsExistsSubQuery() {
+        Preconditions.checkArgument(!getSqlStatement().getInsertSelect().isPresent(), "Do not supported `insert into...select...`");
+    }
+    
+    private void checkValueIsExpected() {
+        Collection<InsertValuesSegment> values = getSqlStatement().getValues();
+        for (InsertValuesSegment insertValuesSegment : values) {
+            boolean isAllMatch = insertValuesSegment.getValues().stream().allMatch(this::isAllowExpressionSegment);
+            Preconditions.checkArgument(isAllMatch, "Value must is literal or parameter marker");
+        }
+    }
+    
+    private void checkOnDuplicateKey() {
+        MySQLInsertStatement sqlStatement = (MySQLInsertStatement) getSqlStatement();
+        Preconditions.checkArgument(!sqlStatement.getOnDuplicateKeyColumns().isPresent(), "Do not supported ON DUPLICATE KEY UPDATE");
+    }
+}
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseQueryCallback.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousSQLStatementChecker.java
similarity index 66%
copy from proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseQueryCallback.java
copy to proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousSQLStatementChecker.java
index c4a300e9d1d..7301cc33769 100644
--- a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseQueryCallback.java
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousSQLStatementChecker.java
@@ -15,25 +15,25 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.proxy.backend.hbase.result;
+package org.apache.shardingsphere.proxy.backend.hbase.checker;
 
-import org.apache.hadoop.hbase.client.Table;
-import java.io.IOException;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
 
 /**
- * HBase query callback.
- * 
- * @param <T> type of result
+ * Check where clause.
+ * @param <T> SQL statement
  */
-public interface HBaseQueryCallback<T> {
+public interface HeterogeneousSQLStatementChecker<T extends SQLStatement> {
     
     /**
-     * Execute in HBase.
-     * 
-     * @param table table
-     * @return execute result
-     * @throws IOException IO exception
+     * Get SQL statement.
+     *
+     * @return SQL statement
      */
-    T executeInHBase(Table table) throws IOException;
+    T getSqlStatement();
     
+    /**
+     * do check.
+     */
+    void execute();
 }
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousSelectStatementChecker.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousSelectStatementChecker.java
new file mode 100644
index 00000000000..cd1cf555e5a
--- /dev/null
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousSelectStatementChecker.java
@@ -0,0 +1,130 @@
+/*
+ * 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.proxy.backend.hbase.checker;
+
+import com.google.common.base.Preconditions;
+import org.apache.shardingsphere.proxy.backend.hbase.context.HBaseContext;
+import org.apache.shardingsphere.proxy.backend.hbase.props.HBasePropertyKey;
+import org.apache.shardingsphere.proxy.backend.hbase.util.HBaseHeterogeneousUtil;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BetweenExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BinaryOperationExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.InExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ColumnProjectionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ProjectionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.ShorthandProjectionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.item.ColumnOrderByItemSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.order.item.OrderByItemSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.PaginationValueSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.limit.LimitSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.limit.NumberLiteralLimitValueSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.WhereSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.table.SimpleTableSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
+import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLSelectStatement;
+import java.util.Optional;
+
+/**
+ * Checker for select statement.
+ */
+public class HeterogeneousSelectStatementChecker extends CommonHeterogeneousSQLStatementChecker<SelectStatement> {
+    
+    public HeterogeneousSelectStatementChecker(final SelectStatement sqlStatement) {
+        super(sqlStatement);
+    }
+    
+    @Override
+    public void execute() {
+        checkProjectionsIsExpected();
+        checkDoNotSupportedSegment();
+        checkSupportedWhereSegment();
+        checkSupportedOrderBySegment();
+    }
+    
+    private void checkDoNotSupportedSegment() {
+        Preconditions.checkArgument(getSqlStatement().getFrom() instanceof SimpleTableSegment, "Only supported SimpleTableSegment");
+        Preconditions.checkArgument(!getSqlStatement().getHaving().isPresent(), "Do not supported having segment");
+        Preconditions.checkArgument(!getSqlStatement().getGroupBy().isPresent(), "Do not supported group by segment");
+        
+        MySQLSelectStatement selectStatement = (MySQLSelectStatement) getSqlStatement();
+        Preconditions.checkArgument(!selectStatement.getWindow().isPresent(), "Do not supported window segment");
+        Preconditions.checkArgument(!selectStatement.getLock().isPresent(), "Do not supported lock segment");
+        Optional<LimitSegment> limitSegment = selectStatement.getLimit();
+        if (limitSegment.isPresent()) {
+            Preconditions.checkArgument(!selectStatement.getLimit().get().getOffset().isPresent(), "Do not supported offset segment");
+            Optional<PaginationValueSegment> paginationSegment = selectStatement.getLimit().flatMap(LimitSegment::getRowCount);
+            Long maxScanLimitSize = HBaseContext.getInstance().getProps().<Long>getValue(HBasePropertyKey.MAX_SCAN_LIMIT_SIZE);
+            paginationSegment.ifPresent(valueSegment -> Preconditions.checkArgument(((NumberLiteralLimitValueSegment) valueSegment).getValue() <= maxScanLimitSize, "row count must less than 5000"));
+        }
+    }
+    
+    private void checkProjectionsIsExpected() {
+        for (ProjectionSegment projectionSegment : getSqlStatement().getProjections().getProjections()) {
+            if (!(projectionSegment instanceof ShorthandProjectionSegment || projectionSegment instanceof ColumnProjectionSegment || HBaseHeterogeneousUtil.isCrcProjectionSegment(
+                    projectionSegment))) {
+                throw new IllegalArgumentException("Only supported ShorthandProjection and ColumnProjection and crc32ExpressionProjection");
+            }
+        }
+    }
+    
+    private void checkSupportedWhereSegment() {
+        Optional<WhereSegment> whereSegment = getSqlStatement().getWhere();
+        if (!whereSegment.isPresent()) {
+            return;
+        }
+        ExpressionSegment whereExpr = whereSegment.get().getExpr();
+        if (whereExpr instanceof BinaryOperationExpression) {
+            checkIsSinglePointQuery(whereSegment);
+        } else if (whereExpr instanceof InExpression) {
+            checkInExpressionIsExpected(whereExpr);
+        } else if (whereExpr instanceof BetweenExpression) {
+            checkBetweenExpressionIsExpected(whereExpr);
+        } else {
+            throw new IllegalArgumentException("Only supported =、in、between...and...");
+        }
+    }
+    
+    private void checkBetweenExpressionIsExpected(final ExpressionSegment whereExpr) {
+        BetweenExpression expression = (BetweenExpression) whereExpr;
+        
+        Preconditions.checkArgument(expression.getLeft() instanceof ColumnSegment, "left segment must is ColumnSegment");
+        String rowKey = ((ColumnSegment) expression.getLeft()).getIdentifier().getValue();
+        boolean isAllowKey = ALLOW_KEYS.stream().anyMatch(each -> each.equalsIgnoreCase(rowKey));
+        Preconditions.checkArgument(isAllowKey, String.format("%s is not a allowed key", rowKey));
+        
+        Preconditions.checkArgument(!expression.isNot(), "Do not supported `not between...and...`");
+        Preconditions.checkArgument(isAllowExpressionSegment(expression.getBetweenExpr()), "between expr must is literal or parameter marker");
+        Preconditions.checkArgument(isAllowExpressionSegment(expression.getAndExpr()), "between expr must is literal or parameter marker");
+    }
+    
+    private void checkSupportedOrderBySegment() {
+        if (!getSqlStatement().getOrderBy().isPresent()) {
+            return;
+        }
+        for (OrderByItemSegment orderByItemSegment : getSqlStatement().getOrderBy().get().getOrderByItems()) {
+            if (!(orderByItemSegment instanceof ColumnOrderByItemSegment)) {
+                throw new IllegalArgumentException("Only simple rowKey order by");
+            }
+            if (!"rowKey".equalsIgnoreCase(((ColumnOrderByItemSegment) orderByItemSegment).getColumn().getIdentifier().getValue())) {
+                throw new IllegalArgumentException("Only simple rowKey order by");
+            }
+        }
+    }
+    
+}
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousUpdateStatementChecker.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousUpdateStatementChecker.java
new file mode 100644
index 00000000000..91289c9a41e
--- /dev/null
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousUpdateStatementChecker.java
@@ -0,0 +1,56 @@
+/*
+ * 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.proxy.backend.hbase.checker;
+
+import com.google.common.base.Preconditions;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.AssignmentSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.InExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.WhereSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.UpdateStatement;
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * Checker for update statement.
+ */
+public class HeterogeneousUpdateStatementChecker extends CommonHeterogeneousSQLStatementChecker<UpdateStatement> {
+    
+    public HeterogeneousUpdateStatementChecker(final UpdateStatement sqlStatement) {
+        super(sqlStatement);
+    }
+    
+    @Override
+    public void execute() {
+        Optional<WhereSegment> whereSegment = getSqlStatement().getWhere();
+        if (whereSegment.isPresent() && whereSegment.get().getExpr() instanceof InExpression) {
+            checkInExpressionIsExpected(whereSegment.get().getExpr());
+        } else {
+            checkIsSinglePointQuery(whereSegment);
+        }
+        checkAssignmentIsOk();
+    }
+    
+    private void checkAssignmentIsOk() {
+        Collection<AssignmentSegment> assignmentSegments = getSqlStatement().getSetAssignment().getAssignments();
+        for (AssignmentSegment assignmentSegment : assignmentSegments) {
+            Preconditions.checkArgument(isAllowExpressionSegment(assignmentSegment.getValue()), "Assigment must is literal or parameter marker");
+            boolean isRowKey = ALLOW_KEYS.stream().anyMatch(each -> each.equalsIgnoreCase(assignmentSegment.getColumns().iterator().next().getIdentifier().getValue()));
+            Preconditions.checkArgument(!isRowKey, "Do not allow update rowKey");
+        }
+    }
+}
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/handler/ErrorHintCommentQueryHandler.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/handler/ErrorHintCommentQueryHandler.java
new file mode 100644
index 00000000000..ab603ced14a
--- /dev/null
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/handler/ErrorHintCommentQueryHandler.java
@@ -0,0 +1,72 @@
+/*
+ * 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.proxy.backend.hbase.handler;
+
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shardingsphere.proxy.backend.hbase.result.HBaseBackendHandler;
+import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
+import org.apache.shardingsphere.proxy.backend.response.header.query.QueryHeader;
+import org.apache.shardingsphere.proxy.backend.response.header.query.QueryResponseHeader;
+import java.sql.Types;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Backend handler for error hint.
+ */
+@Getter
+public final class ErrorHintCommentQueryHandler implements HBaseBackendHandler {
+    
+    private final String hintComment;
+    
+    private int currentIndex;
+    
+    private final String[][] result;
+    
+    public ErrorHintCommentQueryHandler(final String hintComment) {
+        this.hintComment = hintComment;
+        this.currentIndex = 0;
+        int index = 1;
+        this.result = new String[][]{{String.valueOf(index++), "HBase", "supported", "", ""}, {String.valueOf(index), StringUtils.strip(hintComment, "* "), "unsupported", "/", "/"}};
+    }
+    
+    @Override
+    public ResponseHeader execute() {
+        List<QueryHeader> queryHeaders = getColumnNames().stream().map(each -> new QueryHeader("", "", each, each, Types.CHAR, "CHAR", 255, 0, false, false, false, false)).collect(
+                Collectors.toList());
+        return new QueryResponseHeader(queryHeaders);
+    }
+    
+    private Collection<String> getColumnNames() {
+        return Arrays.asList("ID", "Hint", "Status", "Author", "Email");
+    }
+    
+    @Override
+    public boolean next() {
+        currentIndex += 1;
+        return currentIndex <= result.length;
+    }
+    
+    @Override
+    public Collection<Object> getRowDataObjects() {
+        return Arrays.asList(result[currentIndex - 1]);
+    }
+}
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/handler/HBaseBackendQueryHandler.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/handler/HBaseBackendQueryHandler.java
new file mode 100644
index 00000000000..ef98008999c
--- /dev/null
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/handler/HBaseBackendQueryHandler.java
@@ -0,0 +1,64 @@
+/*
+ * 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.proxy.backend.hbase.handler;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.infra.binder.SQLStatementContextFactory;
+import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
+import org.apache.shardingsphere.proxy.backend.hbase.result.HBaseBackendHandler;
+import org.apache.shardingsphere.proxy.backend.hbase.result.query.HBaseQueryResultSet;
+import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
+import org.apache.shardingsphere.proxy.backend.response.header.query.QueryHeader;
+import org.apache.shardingsphere.proxy.backend.response.header.query.QueryResponseHeader;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import java.sql.Types;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Backend handler for HBase.
+ */
+@RequiredArgsConstructor
+@Getter
+public final class HBaseBackendQueryHandler implements HBaseBackendHandler {
+    
+    private final SQLStatement sqlStatement;
+    
+    private final HBaseQueryResultSet resultSet;
+    
+    @Override
+    public ResponseHeader execute() {
+        SQLStatementContext<?> sqlStatementContext = SQLStatementContextFactory.newInstance(null, sqlStatement, "");
+        resultSet.init(sqlStatementContext);
+        List<QueryHeader> queryHeaders = resultSet.getColumnNames().stream().map(each -> new QueryHeader("", "", each, each, Types.CHAR, "CHAR", 255, 0, false, false, false, false))
+                .collect(Collectors.toList());
+        return new QueryResponseHeader(queryHeaders);
+    }
+    
+    @Override
+    public boolean next() {
+        return resultSet.next();
+    }
+    
+    @Override
+    public Collection<Object> getRowDataObjects() {
+        return resultSet.getRowData();
+    }
+}
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseQueryCallback.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseBackendHandler.java
similarity index 70%
copy from proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseQueryCallback.java
copy to proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseBackendHandler.java
index c4a300e9d1d..3ad113e69e9 100644
--- a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseQueryCallback.java
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseBackendHandler.java
@@ -17,23 +17,22 @@
 
 package org.apache.shardingsphere.proxy.backend.hbase.result;
 
-import org.apache.hadoop.hbase.client.Table;
-import java.io.IOException;
+import org.apache.shardingsphere.proxy.backend.handler.ProxyBackendHandler;
+import java.util.Collection;
+import java.util.Collections;
 
 /**
- * HBase query callback.
- * 
- * @param <T> type of result
+ * HBase backend handler.
  */
-public interface HBaseQueryCallback<T> {
+public interface HBaseBackendHandler extends ProxyBackendHandler {
     
     /**
-     * Execute in HBase.
-     * 
-     * @param table table
-     * @return execute result
-     * @throws IOException IO exception
+     * Get row data objects.
+     *
+     * @return row data
      */
-    T executeInHBase(Table table) throws IOException;
+    default Collection<Object> getRowDataObjects() {
+        return Collections.emptyList();
+    }
     
 }
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseQueryCallback.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseQueryCallback.java
index c4a300e9d1d..a64cbfb6305 100644
--- a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseQueryCallback.java
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/HBaseQueryCallback.java
@@ -35,5 +35,4 @@ public interface HBaseQueryCallback<T> {
      * @throws IOException IO exception
      */
     T executeInHBase(Table table) throws IOException;
-    
 }
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/query/HBaseDescribeResultSet.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/query/HBaseDescribeResultSet.java
index 65592f656be..143ebf4e831 100644
--- a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/query/HBaseDescribeResultSet.java
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/query/HBaseDescribeResultSet.java
@@ -82,7 +82,8 @@ public final class HBaseDescribeResultSet implements HBaseQueryResultSet {
     @Override
     public Collection<Object> getRowData() {
         HTableDescriptor descriptor = iterator.next();
-        return Arrays.asList(descriptor.getNameAsString(), descriptor.toStringTableAttributes(), descriptor.getFlushPolicyClassName(), descriptor.getMaxFileSize(),
+        return Arrays.asList(descriptor.getNameAsString(), descriptor.toStringTableAttributes(),
+                descriptor.getFlushPolicyClassName(), descriptor.getMaxFileSize(),
                 descriptor.getMemStoreFlushSize(), descriptor.getPriority(), descriptor.getRegionReplication(), descriptor.getRegionSplitPolicyClassName(),
                 descriptor.toStringCustomizedValues());
     }
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/query/HBaseQueryFactory.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/query/HBaseQueryFactory.java
new file mode 100644
index 00000000000..16bfbe061ec
--- /dev/null
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/query/HBaseQueryFactory.java
@@ -0,0 +1,44 @@
+/*
+ * 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.proxy.backend.hbase.result.query;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.infra.util.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.proxy.backend.handler.ProxyBackendHandler;
+import org.apache.shardingsphere.proxy.backend.hbase.handler.HBaseBackendQueryHandler;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import java.util.Properties;
+
+/**
+ * Heterogeneous database backend handler factory.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class HBaseQueryFactory {
+    
+    /**
+     * Create new instance of heterogeneous database backend handler.
+     *
+     * @param sqlStatement sql statement
+     * @return instance of database backend handler
+     */
+    public static ProxyBackendHandler newInstance(final SQLStatement sqlStatement) {
+        HBaseQueryResultSet resultSet = TypedSPILoader.getService(HBaseQueryResultSet.class, sqlStatement.getClass().getCanonicalName(), new Properties());
+        return new HBaseBackendQueryHandler(sqlStatement, resultSet);
+    }
+}
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/update/HBaseDeleteUpdater.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/update/HBaseDeleteUpdater.java
index 044070a8a93..82b82dd7554 100644
--- a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/update/HBaseDeleteUpdater.java
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/update/HBaseDeleteUpdater.java
@@ -46,5 +46,4 @@ public final class HBaseDeleteUpdater implements HBaseUpdater {
     public String getType() {
         return MySQLDeleteStatement.class.getCanonicalName();
     }
-    
 }
diff --git a/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/update/HBaseUpdateFactory.java b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/update/HBaseUpdateFactory.java
new file mode 100644
index 00000000000..fc9774887cc
--- /dev/null
+++ b/proxy/backend/type/hbase/src/main/java/org/apache/shardingsphere/proxy/backend/hbase/result/update/HBaseUpdateFactory.java
@@ -0,0 +1,44 @@
+/*
+ * 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.proxy.backend.hbase.result.update;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.infra.util.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.proxy.backend.handler.ProxyBackendHandler;
+import org.apache.shardingsphere.proxy.backend.hbase.handler.HBaseBackendUpdateHandler;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import java.util.Properties;
+
+/**
+ * Heterogeneous backend handler factory.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class HBaseUpdateFactory {
+    
+    /**
+     * Create new instance of heterogeneous database backend handler.
+     *
+     * @param sqlStatement sql statement
+     * @return instance of database backend handler
+     */
+    public static ProxyBackendHandler newInstance(final SQLStatement sqlStatement) {
+        HBaseUpdater updater = TypedSPILoader.getService(HBaseUpdater.class, sqlStatement.getClass().getCanonicalName(), new Properties());
+        return new HBaseBackendUpdateHandler(sqlStatement, updater);
+    }
+}
diff --git a/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/CommonHeterogeneousSQLStatementCheckerTest.java b/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/CommonHeterogeneousSQLStatementCheckerTest.java
new file mode 100644
index 00000000000..8fd840fed38
--- /dev/null
+++ b/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/CommonHeterogeneousSQLStatementCheckerTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.proxy.backend.hbase.checker;
+
+import org.apache.shardingsphere.proxy.backend.hbase.result.HBaseSupportedSQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BetweenExpression;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.WhereSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
+import org.junit.Test;
+import java.util.Optional;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public final class CommonHeterogeneousSQLStatementCheckerTest {
+    
+    @Test
+    public void assertIsSinglePoint() {
+        SelectStatement sqlStatement = (SelectStatement) HBaseSupportedSQLStatement.parseSQLStatement("select /*+ hbase */ * from t_order where rowKey = '1'");
+        CommonHeterogeneousSQLStatementChecker<SQLStatement> commonHeterogeneousSQLStatementChecker = new CommonHeterogeneousSQLStatementChecker<>(sqlStatement);
+        commonHeterogeneousSQLStatementChecker.checkIsSinglePointQuery(sqlStatement.getWhere());
+    }
+    
+    @Test
+    public void assertIsSinglePointWithErrorKey() {
+        SelectStatement sqlStatement = (SelectStatement) HBaseSupportedSQLStatement.parseSQLStatement("select /*+ hbase */ * from t_order where a = '1'");
+        CommonHeterogeneousSQLStatementChecker<SQLStatement> commonHeterogeneousSQLStatementChecker = new CommonHeterogeneousSQLStatementChecker<>(sqlStatement);
+        try {
+            commonHeterogeneousSQLStatementChecker.checkIsSinglePointQuery(sqlStatement.getWhere());
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertEquals(e.getMessage(), "a is not a allowed key");
+        }
+    }
+    
+    @Test
+    public void assertIsSinglePointWithErrorOperation() {
+        SelectStatement sqlStatement = (SelectStatement) HBaseSupportedSQLStatement.parseSQLStatement("select /*+ hbase */ * from t_order where rowKey between '1' and '2' ");
+        CommonHeterogeneousSQLStatementChecker<SQLStatement> commonHeterogeneousSQLStatementChecker = new CommonHeterogeneousSQLStatementChecker<>(sqlStatement);
+        try {
+            commonHeterogeneousSQLStatementChecker.checkIsSinglePointQuery(sqlStatement.getWhere());
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertEquals(e.getMessage(), "Only Support BinaryOperationExpression");
+        }
+    }
+    
+    @Test
+    public void assertInExpression() {
+        SelectStatement sqlStatement = (SelectStatement) HBaseSupportedSQLStatement.parseSQLStatement("select /*+ hbase */ * from t_order where rowKey in ('1', '2') ");
+        CommonHeterogeneousSQLStatementChecker<SQLStatement> commonHeterogeneousSQLStatementChecker = new CommonHeterogeneousSQLStatementChecker<>(sqlStatement);
+        Optional<WhereSegment> whereSegment = sqlStatement.getWhere();
+        if (whereSegment.isPresent()) {
+            commonHeterogeneousSQLStatementChecker.checkInExpressionIsExpected(whereSegment.get().getExpr());
+        } else {
+            fail();
+        }
+    }
+    
+    @Test
+    public void assertInExpressionWithNotIn() {
+        SelectStatement sqlStatement = (SelectStatement) HBaseSupportedSQLStatement.parseSQLStatement("select /*+ hbase */ * from t_order where rowKey not in ('1', '2') ");
+        CommonHeterogeneousSQLStatementChecker<SQLStatement> commonHeterogeneousSQLStatementChecker = new CommonHeterogeneousSQLStatementChecker<>(sqlStatement);
+        Optional<WhereSegment> whereSegment = sqlStatement.getWhere();
+        if (whereSegment.isPresent()) {
+            try {
+                commonHeterogeneousSQLStatementChecker.checkInExpressionIsExpected(whereSegment.get().getExpr());
+                fail();
+            } catch (IllegalArgumentException e) {
+                assertEquals(e.getMessage(), "Do not supported `not in`");
+            }
+        } else {
+            fail();
+        }
+    }
+    
+    @Test
+    public void assertInExpressionWithErrorKey() {
+        SelectStatement sqlStatement = (SelectStatement) HBaseSupportedSQLStatement.parseSQLStatement("select /*+ hbase */ * from t_order where a in ('1', '2') ");
+        CommonHeterogeneousSQLStatementChecker<SQLStatement> commonHeterogeneousSQLStatementChecker = new CommonHeterogeneousSQLStatementChecker<>(sqlStatement);
+        Optional<WhereSegment> whereSegment = sqlStatement.getWhere();
+        if (whereSegment.isPresent()) {
+            try {
+                commonHeterogeneousSQLStatementChecker.checkInExpressionIsExpected(whereSegment.get().getExpr());
+                fail();
+            } catch (IllegalArgumentException e) {
+                assertEquals(e.getMessage(), "a is not a allowed key");
+            }
+        } else {
+            fail();
+        }
+    }
+    
+    @Test
+    public void assertIsAllowExpressionSegment() {
+        SelectStatement sqlStatement = (SelectStatement) HBaseSupportedSQLStatement.parseSQLStatement("select /*+ hbase */ * from t_order where rowKey BETWEEN 'v1' AND 'v2' ");
+        CommonHeterogeneousSQLStatementChecker<SQLStatement> commonHeterogeneousSQLStatementChecker = new CommonHeterogeneousSQLStatementChecker<>(sqlStatement);
+        Optional<WhereSegment> whereSegment = sqlStatement.getWhere();
+        if (whereSegment.isPresent()) {
+            BetweenExpression betweenExpression = (BetweenExpression) whereSegment.get().getExpr();
+            assertTrue(commonHeterogeneousSQLStatementChecker.isAllowExpressionSegment(betweenExpression.getBetweenExpr()));
+            assertTrue(commonHeterogeneousSQLStatementChecker.isAllowExpressionSegment(betweenExpression.getAndExpr()));
+        } else {
+            fail();
+        }
+    }
+    
+    @Test
+    public void assertIsAllowExpressionSegmentError() {
+        SelectStatement sqlStatement = (SelectStatement) HBaseSupportedSQLStatement.parseSQLStatement("select /*+ hbase */ * from t_order where rowKey = '1'");
+        CommonHeterogeneousSQLStatementChecker<SQLStatement> commonHeterogeneousSQLStatementChecker = new CommonHeterogeneousSQLStatementChecker<>(sqlStatement);
+        Optional<WhereSegment> whereSegment = sqlStatement.getWhere();
+        if (whereSegment.isPresent()) {
+            assertFalse(commonHeterogeneousSQLStatementChecker.isAllowExpressionSegment(whereSegment.get().getExpr()));
+        } else {
+            fail();
+        }
+    }
+}
diff --git a/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HBaseDatabaseCheckerFactoryTest.java b/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HBaseDatabaseCheckerFactoryTest.java
new file mode 100644
index 00000000000..8984f1c45f4
--- /dev/null
+++ b/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HBaseDatabaseCheckerFactoryTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.proxy.backend.hbase.checker;
+
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQLShowCreateTableStatement;
+import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLDeleteStatement;
+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.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLUpdateStatement;
+import org.junit.Test;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+
+public final class HBaseDatabaseCheckerFactoryTest {
+    
+    @Test
+    public void assertExecuteSelectStatement() {
+        SQLStatement sqlStatement = mock(MySQLSelectStatement.class);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        assertThat(actual, instanceOf(HeterogeneousSelectStatementChecker.class));
+        assertThat(actual.getSqlStatement(), is(sqlStatement));
+    }
+    
+    @Test
+    public void assertExecuteInsertStatement() {
+        SQLStatement sqlStatement = mock(MySQLInsertStatement.class);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        assertThat(actual, instanceOf(HeterogeneousInsertStatementChecker.class));
+        assertThat(actual.getSqlStatement(), is(sqlStatement));
+    }
+    
+    @Test
+    public void assertExecuteUpdateStatement() {
+        SQLStatement sqlStatement = mock(MySQLUpdateStatement.class);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        assertThat(actual, instanceOf(HeterogeneousUpdateStatementChecker.class));
+        assertThat(actual.getSqlStatement(), is(sqlStatement));
+    }
+    
+    @Test
+    public void assertExecuteDeleteStatement() {
+        SQLStatement sqlStatement = mock(MySQLDeleteStatement.class);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        assertThat(actual, instanceOf(HeterogeneousDeleteStatementChecker.class));
+        assertThat(actual.getSqlStatement(), is(sqlStatement));
+    }
+    
+    @Test
+    public void assertExecuteOtherStatement() {
+        SQLStatement sqlStatement = mock(MySQLShowCreateTableStatement.class);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        assertThat(actual, instanceOf(CommonHeterogeneousSQLStatementChecker.class));
+        assertThat(actual.getSqlStatement(), is(sqlStatement));
+    }
+}
diff --git a/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousDeleteStatementCheckerTest.java b/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousDeleteStatementCheckerTest.java
new file mode 100644
index 00000000000..ee5bc56379a
--- /dev/null
+++ b/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousDeleteStatementCheckerTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.proxy.backend.hbase.checker;
+
+import org.apache.shardingsphere.proxy.backend.hbase.result.HBaseSupportedSQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public final class HeterogeneousDeleteStatementCheckerTest {
+    
+    @Rule
+    public ExpectedException expectedEx = ExpectedException.none();
+    
+    @Test
+    public void assertExecuteDeleteStatement() {
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(HBaseSupportedSQLStatement.getDeleteStatement());
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertOperatorIsNotEqual() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Only Supported `=` operator");
+        String sql = "delete /*+ hbase */ from t_test_order where rowKey > 1";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertColumnIsNotRowKey() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("is not a allowed key");
+        String sql = "delete /*+ hbase */ from t_test_order where age = 1";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertLeftIsNotColumn() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("left segment must is ColumnSegment");
+        String sql = "delete /*+ hbase */ from t_test_order where 1 = 1";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertMultiExpression() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Do not supported Multiple expressions");
+        String sql = "DELETE /*+ hbase */ FROM t_order WHERE order_id = ? AND user_id = ? AND status=?";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertWithBetweenExpression() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Only Support BinaryOperationExpression");
+        String sql = "DELETE /*+ hbase */ FROM t_order WHERE rowKey between 1 and 5";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertNotWhereSegment() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Must Have Where Segment");
+        String sql = "DELETE /*+ hbase */ FROM t_order";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+}
diff --git a/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousInsertStatementCheckerTest.java b/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousInsertStatementCheckerTest.java
new file mode 100644
index 00000000000..543ded8e1b9
--- /dev/null
+++ b/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousInsertStatementCheckerTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.proxy.backend.hbase.checker;
+
+import org.apache.shardingsphere.proxy.backend.hbase.result.HBaseSupportedSQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public final class HeterogeneousInsertStatementCheckerTest {
+    
+    @Rule
+    public ExpectedException expectedEx = ExpectedException.none();
+    
+    @Test
+    public void assertExecuteInsertStatement() {
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(HBaseSupportedSQLStatement.getInsertStatement());
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertInsertWithoutRowKey() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("First column must be rowKey");
+        String sql = "INSERT /*+ HBase */ INTO t_order (order_id, user_id, status) VALUES (?, ?, ?)";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertInsertWithoutColumns() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("The inserted column must be explicitly specified");
+        String sql = "INSERT /*+ HBase */ INTO t_order VALUES (?, ?, ?)";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertInsertWithMultipleRowKey() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Cannot contain multiple rowKey");
+        String sql = "INSERT /*+ HBase */ INTO t_order (rowKey, id, status) VALUES (?, ?, ?)";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertInsertWithOnDuplicateKey() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Do not supported ON DUPLICATE KEY UPDATE");
+        String sql = "INSERT /*+ HBase */ INTO t_order (rowKey, user_id, status) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE status = ?";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertInsertWithFunction() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Value must is literal or parameter marker");
+        String sql = "INSERT /*+ HBase */ INTO t_order_item (rowKey, order_id, user_id, status, creation_date) VALUES (?, ?, ?, 'insert', now())";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertInsertWithLiteralAndParameterMarker() {
+        String sql = "INSERT /*+ HBase */ INTO t_order_item(rowKey, order_id, user_id, status, creation_date) VALUES (?, ?, ?, 'insert', '2017-08-08')";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertInsertWithSubQuery() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Do not supported `insert into...select...`");
+        String sql = "INSERT /*+ HBase */ INTO t_order_item(rowKey, order_id, user_id) select rowKey, order_id, user_id from t_order";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+}
diff --git a/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousSelectStatementCheckerTest.java b/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousSelectStatementCheckerTest.java
new file mode 100644
index 00000000000..44ba3fbb630
--- /dev/null
+++ b/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousSelectStatementCheckerTest.java
@@ -0,0 +1,259 @@
+/*
+ * 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.proxy.backend.hbase.checker;
+
+import org.apache.shardingsphere.proxy.backend.hbase.context.HBaseContext;
+import org.apache.shardingsphere.proxy.backend.hbase.props.HBaseProperties;
+import org.apache.shardingsphere.proxy.backend.hbase.props.HBasePropertyKey;
+import org.apache.shardingsphere.proxy.backend.hbase.result.HBaseSupportedSQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public final class HeterogeneousSelectStatementCheckerTest {
+    
+    @Rule
+    public ExpectedException expectedEx = ExpectedException.none();
+    
+    @Before
+    public void setUp() {
+        HBaseProperties props = mock(HBaseProperties.class);
+        when(props.getValue(HBasePropertyKey.MAX_SCAN_LIMIT_SIZE)).thenReturn(5000L);
+        HBaseContext.getInstance().setProps(props);
+    }
+    
+    @Test
+    public void assertSelectStatement() {
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(HBaseSupportedSQLStatement.getSelectStatement());
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectStatementWithLargeRowCount() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("row count must less than 5000");
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement("select /*+ hbase */ * from t_order where id = 1 limit 5001");
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectStatementWithLimitSegment() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Do not supported offset segment");
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement("select /*+ hbase */ * from t_order where id = 1 limit 5 offset 3");
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectStatementWithLockSegment() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Do not supported lock segment");
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement("select /*+ hbase */ * from t_order where id = 1 lock in share mode");
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectStatementWithFunction() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Only supported ShorthandProjection and ColumnProjection");
+        String sql = "SELECT /*+ HBase */ sum(score) FROM person";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectStatementWithJoinStatement() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Only supported SimpleTableSegment");
+        String sql = "SELECT /*+ HBase */ * FROM t_order o JOIN t_order_item i ON o.user_id = i.user_id AND o.order_id = i.order_id";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectStatementWithMultipleInExpression() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("left segment must is ColumnSegment");
+        String sql = "SELECT /*+ HBase */ * FROM t_order WHERE rowKey IN (?, ?) AND id IN (?, ?)";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectStatementWithInExpression() {
+        String sql = "SELECT /*+ HBase */ * from t_order where rowKey in (1, 2, 3)";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectStatementWithErrorKey() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("age is not a allowed key");
+        String sql = "SELECT /*+ HBase */ * from t_order where age in (1, 2, 3)";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertExecuteSelectWithNotIn() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Do not supported `not in`");
+        String sql = "SELECT /*+ HBase */ * from t_order where rowKey not in (1, 2, 3)";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertExecuteSelectWithParameterMarker() {
+        String sql = "SELECT /*+ HBase */ * from t_order where rowKey in (?, ?, ?)";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectStatementUseCrc32() {
+        String sql = "SELECT /*+ HBase */ crc32(concat_ws('#',rowKey)) from t_order where rowKey in (1, 2, 3)";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertExecuteSelectWithErrorInExpression() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Only supported ListExpression");
+        String sql = "SELECT /*+ HBase */ * from t_order where rowKey in (select rowKey from t_order_item)";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertExecuteSelectWithBetween() {
+        String sql = "SELECT /*+ HBase */ * from t_order where rowKey between 1 and 2";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertExecuteSelectWithNotBetween() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Do not supported `not between...and...`");
+        String sql = "SELECT /*+ HBase */ * from t_order where rowKey not between 1 and 2";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertExecuteSelectWithBetweenErrorKey() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("age is not a allowed key");
+        String sql = "SELECT /*+ HBase */ * from t_order where age between 1 and 2";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertExecuteSelectWithErrorBetweenExpr() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("between expr must is literal or parameter marker");
+        String sql = "SELECT /*+ HBase */ * from t_order where rowKey between 1 and now()";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectWithGroupBy() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Do not supported group by segment");
+        String sql = "SELECT /*+ HBase */ * from t_order group by order_id";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectWithNotAllowOperator() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Only Supported `=` operator");
+        String sql = "select /*+ hbase */ * from t_order where rowKey != 1";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectWithNotAllowColumn() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("age is not a allowed key");
+        String sql = "select /*+ hbase */ * from t_order where age = 1";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectWithMultipleExpression() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Do not supported Multiple expressions");
+        String sql = "select /*+ hbase */ * from t_order where rowKey = 1 and age = 2";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectWithNotColumnExpression() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("left segment must is ColumnSegment");
+        String sql = "select /*+ hbase */ * from t_order where 1 = 1";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertSelectWithParameterMarker() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Only supported ShorthandProjection and ColumnProjection");
+        String sql = "select /*+ hbase */ rowKey, name, ? from t_order where rowKey = 'kid'";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+}
diff --git a/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousUpdateStatementCheckerTest.java b/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousUpdateStatementCheckerTest.java
new file mode 100644
index 00000000000..0ac5d34ebeb
--- /dev/null
+++ b/proxy/backend/type/hbase/src/test/java/org/apache/shardingsphere/proxy/backend/hbase/checker/HeterogeneousUpdateStatementCheckerTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.proxy.backend.hbase.checker;
+
+import org.apache.shardingsphere.proxy.backend.hbase.result.HBaseSupportedSQLStatement;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public final class HeterogeneousUpdateStatementCheckerTest {
+    
+    @Rule
+    public ExpectedException expectedEx = ExpectedException.none();
+    
+    @Test
+    public void assertExecuteUpdateStatement() {
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(HBaseSupportedSQLStatement.getUpdateStatement());
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertUpdateWithFunction() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Assigment must is literal or parameter marker");
+        String sql = "update /*+ hbase */ t_test_order set age = 10, name = 'bob', time = now() where rowKey = 1";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertOperatorIsNotEqual() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Only Supported `=` operator");
+        String sql = "update /*+ hbase */ t_test_order set age = 10 where rowKey > 1";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertColumnIsNotRowKey() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("is not a allowed key");
+        String sql = "update /*+ hbase */ t_test_order set age = 10 where age = 1";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertLeftIsNotColumn() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("left segment must is ColumnSegment");
+        String sql = "update /*+ hbase */ t_test_order set age = 10 where 1 = 1";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertMultiExpression() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Do not supported Multiple expressions");
+        String sql = "update /*+ hbase */ t_test_order set age = 10 WHERE order_id = ? AND user_id = ? AND status=?";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertNotWhereSegment() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Must Have Where Segment");
+        String sql = "update /*+ hbase */ t_test_order set age = 10 ";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+    
+    @Test
+    public void assertUpdateRowKey() {
+        expectedEx.expect(IllegalArgumentException.class);
+        expectedEx.expectMessage("Do not allow update rowKey");
+        String sql = "update /*+ hbase */ t_test_order set rowKey = 10 where rowKey = 'kid'";
+        SQLStatement sqlStatement = HBaseSupportedSQLStatement.parseSQLStatement(sql);
+        HeterogeneousSQLStatementChecker<?> actual = HBaseCheckerFactory.newInstance(sqlStatement);
+        actual.execute();
+    }
+}