1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package edu.internet2.middleware.subject.provider;
21
22 import java.sql.Connection;
23 import java.sql.SQLException;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28
29 import org.apache.commons.lang.StringUtils;
30
31 import edu.internet2.middleware.subject.SubjectUtils;
32
33
34
35
36
37
38 public enum JdbcDatabaseType {
39
40
41 oracle {
42
43
44
45
46
47 @Override
48 public String pageQuery(String query, int pageSize) {
49
50 String selectPart = selectPart(query);
51 if (selectPart == null) {
52 return query;
53 }
54
55 List<String> aliases = columnAliases(selectPart);
56
57 if (aliases == null) {
58 return query;
59 }
60
61
62 StringBuilder result = new StringBuilder("select ");
63
64 for (int i=0;i<aliases.size();i++) {
65 result.append(aliases.get(i));
66 if (i < (aliases.size()-1)) {
67 result.append(", ");
68 }
69 }
70 result.append(" from (").append(query).append(") where rownum <= ").append(pageSize);
71 return result.toString();
72 }
73
74
75
76
77
78
79 @Override
80 public boolean matchesUrlDefinitely(String url) {
81 return url != null && url.toLowerCase().startsWith("jdbc:oracle:");
82 }
83
84
85
86
87
88 @Override
89 public boolean matchesUrlMaybe(String url) {
90 return url != null && url.toLowerCase().contains("oracle");
91 }
92
93 },
94
95
96 mysql {
97
98
99
100
101
102 @Override
103 public String pageQuery(String query, int pageSize) {
104 return query + " limit 0," + pageSize;
105 }
106
107
108
109
110
111 @Override
112 public boolean matchesUrlDefinitely(String url) {
113 return url != null && url.toLowerCase().startsWith("jdbc:mysql:");
114 }
115
116
117
118
119
120 @Override
121 public boolean matchesUrlMaybe(String url) {
122 return url != null && url.toLowerCase().contains("mysql");
123 }
124 },
125
126
127 postgres {
128
129
130
131
132
133 @Override
134 public String pageQuery(String query, int pageSize) {
135 return query + " limit " + pageSize;
136 }
137
138
139
140
141
142 @Override
143 public boolean matchesUrlDefinitely(String url) {
144 return url != null && url.toLowerCase().startsWith("jdbc:postgresql:");
145 }
146
147
148
149
150
151 @Override
152 public boolean matchesUrlMaybe(String url) {
153 return url != null && url.toLowerCase().contains("postgres");
154 }
155
156 },
157
158
159 hsqldb {
160
161
162
163
164
165 @Override
166 public String pageQuery(String query, int pageSize) {
167 return null;
168 }
169
170
171
172
173
174 @Override
175 public boolean matchesUrlDefinitely(String url) {
176 return url != null && url.toLowerCase().startsWith("jdbc:hsqldb:");
177 }
178
179
180
181
182
183 @Override
184 public boolean matchesUrlMaybe(String url) {
185 return url != null && url.toLowerCase().contains("hsql");
186 }
187 };
188
189
190
191
192
193
194 public static JdbcDatabaseType resolveDatabaseType(Connection connection) {
195 String url = null;
196
197 try {
198 url = connection.getMetaData().getURL();
199 } catch (SQLException sqle) {
200 return null;
201 }
202
203 for (JdbcDatabaseType jdbcDatabaseType : JdbcDatabaseType.values()) {
204 if (jdbcDatabaseType.matchesUrlDefinitely(url)) {
205 return jdbcDatabaseType;
206 }
207 }
208
209 for (JdbcDatabaseType jdbcDatabaseType : JdbcDatabaseType.values()) {
210 if (jdbcDatabaseType.matchesUrlMaybe(url)) {
211 return jdbcDatabaseType;
212 }
213 }
214
215 return null;
216 }
217
218
219 private static Pattern selectClausePattern = Pattern.compile("^(.*?\\s)(from\\s.*)$", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
220
221
222 private static Pattern lastWordPattern = Pattern.compile("^.*\\s(.*)$", Pattern.DOTALL);
223
224
225
226
227
228
229 public static List<String> columnAliases(String fromClause) {
230 if (fromClause == null) {
231 return null;
232 }
233 String[] cols = SubjectUtils.splitTrim(fromClause, ",");
234 List<String> result = new ArrayList<String>();
235
236 String alias = null;
237 for (String col : cols) {
238 Matcher matcher = lastWordPattern.matcher(col);
239
240 if (matcher.matches()) {
241 alias = matcher.group(1);
242 } else {
243 alias = col;
244 }
245
246 if (StringUtils.equals("*", alias)) {
247 return null;
248 }
249 result.add(alias);
250 }
251 return result;
252 }
253
254
255
256
257
258
259 public static String selectPart(String query) {
260
261 if (query == null) {
262 return null;
263 }
264
265 String fromAndAfter = query;
266 String upToFrom = "";
267
268 while (true) {
269 Matcher matcher = selectClausePattern.matcher(fromAndAfter);
270
271 if (!matcher.matches()) {
272 return null;
273 }
274
275 upToFrom += matcher.group(1);
276 fromAndAfter = matcher.group(2);
277
278
279 int leftParenCount = StringUtils.countMatches(upToFrom, "(");
280 int rightParenCount = StringUtils.countMatches(upToFrom, ")");
281
282 if (leftParenCount == rightParenCount) {
283 return upToFrom;
284 }
285 }
286
287 }
288
289
290
291
292
293
294
295 public abstract String pageQuery(String query, int pageSize);
296
297
298
299
300
301
302 public abstract boolean matchesUrlDefinitely(String url);
303
304
305
306
307
308
309 public abstract boolean matchesUrlMaybe(String url);
310
311
312
313
314
315
316
317
318
319
320 public static JdbcDatabaseType valueOfIgnoreCase(String string, boolean exceptionOnNull) {
321 return SubjectUtils.enumValueOfIgnoreCase(JdbcDatabaseType.class,
322 string, exceptionOnNull);
323
324 }
325
326
327
328 }