1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package com.finalist.tools.database;
19
20 /***
21 * Utility class to indent queries and insert newlines
22 * usage: create new object with string to format, and
23 * call toString on the object.
24 *
25 *@author mdemare
26 */
27 public class SqlPretty {
28
29
30 private final static String[] KEYWORD = {"from", "where", "having", "group by",
31 "order by", "and", "set", "delete", "insert", "select", "or"};
32
33 private final static int INDENT_SPACE = 3;
34
35 private StringBuffer sb = new StringBuffer();
36 private int i = -1;
37 private int indent = 0;
38 private int keywordIndent = 0;
39 private boolean inString = false;
40 private boolean escaped = false;
41 private boolean skipspace = false;
42 private String sql;
43
44 private String result;
45
46
47 /***
48 *Constructor for the SqlPretty object
49 *
50 *@param sql query string to format
51 */
52 public SqlPretty(String sql) {
53 this.sql = sql;
54 while (++i < sql.length()) {
55 char c = sql.charAt(i);
56
57
58 if (skipspace) {
59 if (c == ' ' || c == '\t') {
60 continue;
61 }
62 else {
63 skipspace = false;
64 }
65 }
66
67
68 if (escaped) {
69 sb.append(c);
70 escaped = false;
71 continue;
72 }
73
74
75 if (c == '//') {
76 escaped = true;
77 sb.append(c);
78 continue;
79 }
80
81
82 if (c == '\'' || c == '\"') {
83 inString = !inString;
84 sb.append(c);
85 continue;
86 }
87
88
89 if (inString) {
90 sb.append(c);
91 continue;
92 }
93
94 switch (c) {
95
96 case '(':
97 indent++;
98
99 case ' ':
100
101 if (!keyword()) {
102 sb.append(c);
103 }
104 break;
105
106 case ')':
107 indent--;
108 sb.append(c);
109 break;
110
111 case ',':
112 sb.append(c + "\n");
113 indent(keywordIndent + indent * INDENT_SPACE);
114 skipspace = true;
115 break;
116
117 default:
118 sb.append(c);
119 }
120 }
121
122 result = sb.toString();
123 }
124
125
126 /***
127 * Compare word that starts after current char with list of keywords.
128 * New line and extra indentation if found.
129 * We use INDENT_SPACE spaces for each level of parentheses,
130 * and KEYWORD.length + 1 for the most recently seen keyword.
131 */
132 private boolean keyword() {
133 for (int j = 0; j < KEYWORD.length; j++) {
134 if (i + KEYWORD[j].length() + 1 >= sql.length()) {
135 continue;
136 }
137 if (KEYWORD[j].equalsIgnoreCase(sql.substring(i + 1, i + KEYWORD[j].length() + 1))) {
138 sb.append("\n");
139 indent(indent * INDENT_SPACE);
140 if (sql.charAt(i) == '(') {
141 sb.append('(');
142 }
143 sb.append(KEYWORD[j]);
144 i += KEYWORD[j].length();
145 keywordIndent = KEYWORD[j].length() + 1;
146 return true;
147 }
148 }
149 return false;
150 }
151
152
153 /***
154 * Description of the Method
155 *
156 *@return Description of the Return Value
157 */
158 public String toString() {
159 return result;
160 }
161
162
163 /***
164 * The main program for the SqlPretty class
165 *
166 *@param args The command line arguments
167 *@throws Exception Description of the Exception
168 */
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185 /***
186 * Repeat a string n times to form a new string.
187 *
188 *@param str String to repeat
189 *@param repeat int number of times to repeat
190 *@return String with repeated string
191 *@throws NegativeArraySizeException if repeat < 0
192 *@throws NullPointerException if str is null
193 */
194 private static String repeat(String str, int repeat) {
195 StringBuffer buffer = new StringBuffer(repeat * str.length());
196 for (int i = 0; i < repeat; i++) {
197 buffer.append(str);
198 }
199 return buffer.toString();
200 }
201
202
203 /***
204 * Description of the Method
205 *
206 *@param str Description of the Parameter
207 *@param delim Description of the Parameter
208 *@return Description of the Return Value
209 */
210 private static String strip(String str, String delim) {
211 str = stripStart(str, delim);
212 return stripEnd(str, delim);
213 }
214
215
216 /***
217 * Description of the Method
218 *
219 *@param str Description of the Parameter
220 *@param strip Description of the Parameter
221 *@return Description of the Return Value
222 */
223 private static String stripStart(String str, String strip) {
224 if (str == null) {
225 return null;
226 }
227 int start = 0;
228 int sz = str.length();
229
230 if (strip == null) {
231 while ((start != sz) && Character.isWhitespace(str.charAt(start))) {
232 start++;
233 }
234 }
235 else {
236 while ((start != sz) && (strip.indexOf(str.charAt(start)) != -1)) {
237 start++;
238 }
239 }
240 return str.substring(start);
241 }
242
243
244 /***
245 * Description of the Method
246 *
247 *@param str Description of the Parameter
248 *@param strip Description of the Parameter
249 *@return Description of the Return Value
250 */
251 private static String stripEnd(String str, String strip) {
252 if (str == null) {
253 return null;
254 }
255 int end = str.length();
256 if (strip == null) {
257 while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) {
258 end--;
259 }
260 }
261 else {
262 while ((end != 0) && (strip.indexOf(str.charAt(end - 1)) != -1)) {
263 end--;
264 }
265 }
266 return str.substring(0, end);
267 }
268
269
270 private void indent(int s) {
271 sb.append(repeat(" ", s));
272 }
273
274
275 }