1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.infra.hint;
19
20 import com.google.common.base.Splitter;
21 import lombok.AccessLevel;
22 import lombok.NoArgsConstructor;
23
24 import java.math.BigInteger;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map.Entry;
30 import java.util.Objects;
31 import java.util.Properties;
32
33
34
35
36 @NoArgsConstructor(access = AccessLevel.PRIVATE)
37 public final class SQLHintUtils {
38
39 private static final String SQL_COMMENT_SUFFIX = "*/";
40
41 private static final String SQL_HINT_SPLIT = ",";
42
43 private static final String SQL_HINT_VALUE_SPLIT = "=";
44
45 private static final String SQL_HINT_VALUE_COLLECTION_SPLIT = " ";
46
47 private static final int SQL_HINT_VALUE_SIZE = 2;
48
49
50
51
52
53
54
55 public static HintValueContext extractHint(final String sql) {
56 if (!startWithHint(sql, SQLHintTokenEnum.SQL_START_HINT_TOKEN)) {
57 return new HintValueContext();
58 }
59 HintValueContext result = new HintValueContext();
60 String hintText = sql.substring(0, sql.indexOf(SQL_COMMENT_SUFFIX) + 2);
61 Properties hintProps = getSQLHintProps(hintText);
62 if (containsPropertyKey(hintProps, SQLHintPropertiesKey.DATASOURCE_NAME_KEY)) {
63 result.setDataSourceName(getProperty(hintProps, SQLHintPropertiesKey.DATASOURCE_NAME_KEY));
64 }
65 if (containsPropertyKey(hintProps, SQLHintPropertiesKey.WRITE_ROUTE_ONLY_KEY)) {
66 result.setWriteRouteOnly(Boolean.parseBoolean(getProperty(hintProps, SQLHintPropertiesKey.WRITE_ROUTE_ONLY_KEY)));
67 }
68 if (containsPropertyKey(hintProps, SQLHintPropertiesKey.USE_TRAFFIC_KEY)) {
69 result.setUseTraffic(Boolean.parseBoolean(getProperty(hintProps, SQLHintPropertiesKey.USE_TRAFFIC_KEY)));
70 }
71 if (containsPropertyKey(hintProps, SQLHintPropertiesKey.SKIP_SQL_REWRITE_KEY)) {
72 result.setSkipSQLRewrite(Boolean.parseBoolean(getProperty(hintProps, SQLHintPropertiesKey.SKIP_SQL_REWRITE_KEY)));
73 }
74 if (containsPropertyKey(hintProps, SQLHintPropertiesKey.DISABLE_AUDIT_NAMES_KEY)) {
75 String property = getProperty(hintProps, SQLHintPropertiesKey.DISABLE_AUDIT_NAMES_KEY);
76 result.getDisableAuditNames().addAll(getSplitterSQLHintValue(property));
77 }
78 if (containsPropertyKey(hintProps, SQLHintPropertiesKey.SHADOW_KEY)) {
79 result.setShadow(Boolean.parseBoolean(getProperty(hintProps, SQLHintPropertiesKey.SHADOW_KEY)));
80 }
81 for (Entry<Object, Object> entry : hintProps.entrySet()) {
82 Comparable<?> value = entry.getValue() instanceof Comparable ? (Comparable<?>) entry.getValue() : Objects.toString(entry.getValue());
83 if (containsPropertyKey(Objects.toString(entry.getKey()), SQLHintPropertiesKey.SHARDING_DATABASE_VALUE_KEY)) {
84 result.getShardingDatabaseValues().put(Objects.toString(entry.getKey()).toUpperCase(), value);
85 }
86 if (containsPropertyKey(Objects.toString(entry.getKey()), SQLHintPropertiesKey.SHARDING_TABLE_VALUE_KEY)) {
87 result.getShardingTableValues().put(Objects.toString(entry.getKey()).toUpperCase(), value);
88 }
89 }
90 return result;
91 }
92
93
94
95
96
97
98
99 public static String removeHint(final String sql) {
100 return startWithHint(sql, SQLHintTokenEnum.SQL_START_HINT_TOKEN) ? sql.substring(sql.indexOf(SQL_COMMENT_SUFFIX) + 2).trim() : sql;
101 }
102
103 private static Properties getSQLHintProps(final String comment) {
104 Properties result = new Properties();
105 int startIndex = getStartIndex(comment, SQLHintTokenEnum.SQL_START_HINT_TOKEN, SQLHintTokenEnum.SQL_HINT_TOKEN);
106 if (startIndex < 0) {
107 return result;
108 }
109 int endIndex = comment.endsWith(SQL_COMMENT_SUFFIX) ? comment.indexOf(SQL_COMMENT_SUFFIX) : comment.length();
110 Collection<String> sqlHints = Splitter.on(SQL_HINT_SPLIT).trimResults().splitToList(comment.substring(startIndex, endIndex).trim());
111 for (String each : sqlHints) {
112 List<String> hintValues = Splitter.on(SQL_HINT_VALUE_SPLIT).limit(SQL_HINT_VALUE_SIZE).trimResults().splitToList(each);
113 if (SQL_HINT_VALUE_SIZE == hintValues.size()) {
114 result.put(hintValues.get(0), convert(hintValues.get(1)));
115 }
116 }
117 return result;
118 }
119
120 private static int getStartIndex(final String comment, final SQLHintTokenEnum sqlStartHintToken, final SQLHintTokenEnum sqlHintToken) {
121 String lowerCaseComment = comment.toLowerCase();
122 int result = lowerCaseComment.startsWith(sqlStartHintToken.getAlias().toLowerCase())
123 ? lowerCaseComment.indexOf(sqlHintToken.getAlias())
124 : lowerCaseComment.indexOf(sqlHintToken.getKey());
125 if (result >= 0) {
126 return result + sqlHintToken.getKey().length();
127 }
128 return result;
129 }
130
131 private static Object convert(final String value) {
132 try {
133 return new BigInteger(value);
134 } catch (final NumberFormatException ignored) {
135 return value;
136 }
137 }
138
139 private static boolean startWithHint(final String sql, final SQLHintTokenEnum sqlStartHintToken) {
140 return null != sql && (sql.startsWith(sqlStartHintToken.getKey()) || sql.startsWith(sqlStartHintToken.getAlias()));
141 }
142
143 private static boolean containsPropertyKey(final Properties hintProps, final SQLHintPropertiesKey sqlHintPropsKey) {
144 return hintProps.containsKey(sqlHintPropsKey.getKey()) || hintProps.containsKey(sqlHintPropsKey.getAlias());
145 }
146
147 private static boolean containsPropertyKey(final String hintPropKey, final SQLHintPropertiesKey sqlHintPropsKey) {
148 return hintPropKey.contains(sqlHintPropsKey.getKey()) || hintPropKey.contains(sqlHintPropsKey.getAlias());
149 }
150
151 private static String getProperty(final Properties hintProps, final SQLHintPropertiesKey sqlHintPropsKey) {
152 String result = hintProps.getProperty(sqlHintPropsKey.getKey());
153 return null == result ? hintProps.getProperty(sqlHintPropsKey.getAlias()) : result;
154 }
155
156 private static Collection<String> getSplitterSQLHintValue(final String property) {
157 return property.isEmpty() ? Collections.emptySet() : new HashSet<>(Splitter.on(SQLHintUtils.SQL_HINT_VALUE_COLLECTION_SPLIT).omitEmptyStrings().trimResults().splitToList(property));
158 }
159 }