1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.encrypt.merge.dal.show;
19
20 import org.apache.shardingsphere.encrypt.exception.syntax.UnsupportedEncryptSQLException;
21 import org.apache.shardingsphere.encrypt.rule.EncryptRule;
22 import org.apache.shardingsphere.encrypt.rule.EncryptTable;
23 import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
24 import org.apache.shardingsphere.infra.binder.context.type.TableAvailable;
25 import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
26 import org.apache.shardingsphere.infra.merge.result.MergedResult;
27 import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
28 import org.apache.shardingsphere.infra.parser.SQLParserEngine;
29 import org.apache.shardingsphere.parser.rule.SQLParserRule;
30 import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.column.ColumnDefinitionSegment;
31 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
32 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.CreateTableStatement;
33
34 import java.io.InputStream;
35 import java.io.Reader;
36 import java.sql.SQLException;
37 import java.sql.SQLFeatureNotSupportedException;
38 import java.util.ArrayList;
39 import java.util.Calendar;
40 import java.util.List;
41 import java.util.Optional;
42
43
44
45
46 public abstract class EncryptShowCreateTableMergedResult implements MergedResult {
47
48 private static final String COMMA = ", ";
49
50 private static final int CREATE_TABLE_DEFINITION_INDEX = 2;
51
52 private final String tableName;
53
54 private final EncryptRule encryptRule;
55
56 private final SQLParserEngine sqlParserEngine;
57
58 protected EncryptShowCreateTableMergedResult(final RuleMetaData globalRuleMetaData, final SQLStatementContext sqlStatementContext, final EncryptRule encryptRule) {
59 ShardingSpherePreconditions.checkState(sqlStatementContext instanceof TableAvailable && 1 == ((TableAvailable) sqlStatementContext).getAllTables().size(),
60 () -> new UnsupportedEncryptSQLException("SHOW CREATE TABLE FOR MULTI TABLE"));
61 tableName = ((TableAvailable) sqlStatementContext).getAllTables().iterator().next().getTableName().getIdentifier().getValue();
62 this.encryptRule = encryptRule;
63 sqlParserEngine = globalRuleMetaData.getSingleRule(SQLParserRule.class).getSQLParserEngine(sqlStatementContext.getDatabaseType());
64 }
65
66 @Override
67 public final boolean next() throws SQLException {
68 return nextValue();
69 }
70
71 @Override
72 public final Object getValue(final int columnIndex, final Class<?> type) throws SQLException {
73 if (CREATE_TABLE_DEFINITION_INDEX == columnIndex) {
74 String result = getOriginalValue(CREATE_TABLE_DEFINITION_INDEX, type).toString();
75 Optional<EncryptTable> encryptTable = encryptRule.findEncryptTable(tableName);
76 if (!encryptTable.isPresent() || !result.contains("(")) {
77 return result;
78 }
79 CreateTableStatement createTableStatement = (CreateTableStatement) sqlParserEngine.parse(result, false);
80 List<ColumnDefinitionSegment> columnDefinitions = new ArrayList<>(createTableStatement.getColumnDefinitions());
81 StringBuilder builder = new StringBuilder(result.substring(0, columnDefinitions.get(0).getStartIndex()));
82 for (ColumnDefinitionSegment each : columnDefinitions) {
83 findLogicColumnDefinition(each, encryptTable.get(), result).ifPresent(optional -> builder.append(optional).append(COMMA));
84 }
85
86 builder.delete(builder.length() - COMMA.length(), builder.length()).append(result.substring(columnDefinitions.get(columnDefinitions.size() - 1).getStopIndex() + 1));
87 return builder.toString();
88 }
89 return getOriginalValue(columnIndex, type);
90 }
91
92 private Optional<String> findLogicColumnDefinition(final ColumnDefinitionSegment columnDefinition, final EncryptTable encryptTable, final String sql) {
93 ColumnSegment columnSegment = columnDefinition.getColumnName();
94 String columnName = columnSegment.getIdentifier().getValue();
95 if (encryptTable.isCipherColumn(columnName)) {
96 String logicColumn = encryptTable.getLogicColumnByCipherColumn(columnName);
97 return Optional.of(sql.substring(columnDefinition.getStartIndex(), columnSegment.getStartIndex())
98 + columnSegment.getIdentifier().getQuoteCharacter().wrap(logicColumn) + sql.substring(columnSegment.getStopIndex() + 1, columnDefinition.getStopIndex() + 1));
99 }
100 if (isDerivedColumn(encryptTable, columnName)) {
101 return Optional.empty();
102 }
103 return Optional.of(sql.substring(columnDefinition.getStartIndex(), columnDefinition.getStopIndex() + 1));
104 }
105
106 private boolean isDerivedColumn(final EncryptTable encryptTable, final String columnName) {
107 return encryptTable.isAssistedQueryColumn(columnName) || encryptTable.isLikeQueryColumn(columnName);
108 }
109
110 @Override
111 public final Object getCalendarValue(final int columnIndex, final Class<?> type, final Calendar calendar) throws SQLException {
112 throw new SQLFeatureNotSupportedException("");
113 }
114
115 @Override
116 public final InputStream getInputStream(final int columnIndex, final String type) throws SQLException {
117 throw new SQLFeatureNotSupportedException("");
118 }
119
120 @Override
121 public Reader getCharacterStream(final int columnIndex) throws SQLException {
122 throw new SQLFeatureNotSupportedException("");
123 }
124
125 protected abstract boolean nextValue() throws SQLException;
126
127 protected abstract Object getOriginalValue(int columnIndex, Class<?> type) throws SQLException;
128 }