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();
+ }
+}