1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.proxy.backend.hbase.converter.type;
19
20 import com.google.common.base.Preconditions;
21 import lombok.RequiredArgsConstructor;
22 import org.apache.hadoop.hbase.client.Get;
23 import org.apache.hadoop.hbase.client.Query;
24 import org.apache.hadoop.hbase.client.Scan;
25 import org.apache.hadoop.hbase.util.Bytes;
26 import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
27 import org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext;
28 import org.apache.shardingsphere.proxy.backend.hbase.bean.HBaseOperation;
29 import org.apache.shardingsphere.proxy.backend.hbase.converter.HBaseOperationConverter;
30 import org.apache.shardingsphere.proxy.backend.hbase.converter.HBaseRowKeyExtractor;
31 import org.apache.shardingsphere.proxy.backend.hbase.converter.operation.HBaseSelectOperation;
32 import org.apache.shardingsphere.proxy.backend.hbase.util.HBaseHeterogeneousUtils;
33 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BetweenExpression;
34 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BinaryOperationExpression;
35 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
36 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.InExpression;
37 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.LiteralExpressionSegment;
38 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.limit.NumberLiteralLimitValueSegment;
39 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.predicate.WhereSegment;
40 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLSelectStatement;
41
42 import java.util.Arrays;
43 import java.util.Collections;
44 import java.util.List;
45 import java.util.Optional;
46 import java.util.stream.Collectors;
47
48
49
50
51 @RequiredArgsConstructor
52 public final class HBaseSelectOperationConverter implements HBaseOperationConverter {
53
54 private final SQLStatementContext sqlStatementContext;
55
56 @Override
57 public HBaseOperation convert() {
58 SelectStatementContext selectStatementContext = (SelectStatementContext) sqlStatementContext;
59 Optional<WhereSegment> whereSegment = selectStatementContext.getWhereSegments().stream().findFirst();
60 Preconditions.checkArgument(whereSegment.isPresent(), "Where segment is absent.");
61 return whereSegment.get().getExpr() instanceof BinaryOperationExpression || whereSegment.get().getExpr() instanceof InExpression
62 ? createGetOperation(selectStatementContext, whereSegment.get())
63 : createScanOperation(selectStatementContext, whereSegment.get());
64 }
65
66 private HBaseOperation createGetOperation(final SelectStatementContext selectStatementContext, final WhereSegment whereSegment) {
67 ExpressionSegment expr = whereSegment.getExpr();
68 List<Get> gets = getRowKeys(expr).stream().map(each -> new Get(Bytes.toBytes(each))).collect(Collectors.toList());
69 if (!HBaseHeterogeneousUtils.isUseShorthandProjection(selectStatementContext)) {
70 for (Get each : gets) {
71 appendColumns(each, selectStatementContext);
72 }
73 }
74 String tableName = selectStatementContext.getTablesContext().getTableNames().iterator().next();
75 return expr instanceof InExpression ? new HBaseOperation(tableName, new HBaseSelectOperation(gets)) : new HBaseOperation(tableName, gets.get(0));
76 }
77
78 private List<String> getRowKeys(final ExpressionSegment expr) {
79 return expr instanceof InExpression ? HBaseRowKeyExtractor.getRowKeys((InExpression) expr) : Collections.singletonList(HBaseRowKeyExtractor.getRowKey((BinaryOperationExpression) expr));
80 }
81
82 private HBaseOperation createScanOperation(final SelectStatementContext selectStatementContext, final WhereSegment whereSegment) {
83 Scan scan = new Scan();
84 if (whereSegment.getExpr() instanceof BetweenExpression) {
85 appendBetween(scan, whereSegment.getExpr(), false);
86 }
87 if (!HBaseHeterogeneousUtils.isUseShorthandProjection(selectStatementContext)) {
88 appendColumns(scan, selectStatementContext);
89 }
90 appendLimit(scan, selectStatementContext);
91 return new HBaseOperation(selectStatementContext.getTablesContext().getTableNames().iterator().next(), scan);
92 }
93
94 private void appendColumns(final Query query, final SelectStatementContext selectStatementContext) {
95 if (query instanceof Get) {
96 selectStatementContext.getColumnSegments().forEach(each -> ((Get) query).addColumn(Bytes.toBytes("i"), Bytes.toBytes(String.valueOf(each))));
97 } else {
98 selectStatementContext.getColumnSegments().forEach(each -> ((Scan) query).addColumn(Bytes.toBytes("i"), Bytes.toBytes(String.valueOf(each))));
99 }
100 }
101
102 private void appendBetween(final Scan scan, final ExpressionSegment expressionSegment, final boolean reversed) {
103 BetweenExpression betweenExpr = (BetweenExpression) expressionSegment;
104 String startRowKey = ((LiteralExpressionSegment) betweenExpr.getBetweenExpr()).getLiterals().toString();
105 String stopRowKey = ((LiteralExpressionSegment) betweenExpr.getAndExpr()).getLiterals().toString();
106 if (null != startRowKey && null != stopRowKey) {
107 if (reversed) {
108 scan.withStopRow(calBytes(startRowKey, 0), true);
109
110 scan.withStartRow(calBytes(stopRowKey + "~", 0), true);
111 } else {
112 scan.withStartRow(calBytes(startRowKey, 0), true);
113 scan.withStopRow(calBytes(stopRowKey + "~", 0), true);
114 }
115 }
116 }
117
118 private byte[] calBytes(final String row, final int step) {
119 byte[] rowByte = Bytes.toBytes(row);
120 byte[] result = Arrays.copyOf(rowByte, rowByte.length);
121 result[result.length - 1] = (byte) (result[result.length - 1] + step);
122 return result;
123 }
124
125 private void appendLimit(final Scan scan, final SelectStatementContext selectStatementContext) {
126
127 MySQLSelectStatement selectStatement = (MySQLSelectStatement) selectStatementContext.getSqlStatement();
128 if (selectStatement.getLimit().isPresent()) {
129 selectStatement.getLimit().get().getRowCount().ifPresent(optional -> scan.setLimit((int) ((NumberLiteralLimitValueSegment) optional).getValue()));
130 }
131 }
132 }