View Javadoc

1   /*   Copyright (C) 2004 Finalist IT Group
2    *
3    *   This file is part of JAG - the Java J2EE Application Generator
4    *
5    *   JAG is free software; you can redistribute it and/or modify
6    *   it under the terms of the GNU General Public License as published by
7    *   the Free Software Foundation; either version 2 of the License, or
8    *   (at your option) any later version.
9    *   JAG is distributed in the hope that it will be useful,
10   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   *   GNU General Public License for more details.
13   *   You should have received a copy of the GNU General Public License
14   *   along with JAG; if not, write to the Free Software
15   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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     // the keywords that should produce a linefeed
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           // skip spaces after commas
58           if (skipspace) {
59              if (c == ' ' || c == '\t') {
60                 continue;
61              }
62              else {
63                 skipspace = false;
64              }
65           }
66  
67           // previous char was a backspace
68           if (escaped) {
69              sb.append(c);
70              escaped = false;
71              continue;
72           }
73  
74           // this char is a backspace
75           if (c == '//') {
76              escaped = true;
77              sb.append(c);
78              continue;
79           }
80  
81           // entering or leaving string
82           if (c == '\'' || c == '\"') {
83              inString = !inString;
84              sb.append(c);
85              continue;
86           }
87  
88           // within a string
89           if (inString) {
90              sb.append(c);
91              continue;
92           }
93  
94           switch (c) {
95              // increase indentation and check for keyword
96              case '(':
97                 indent++;
98                 // check for keyword
99              case ' ':
100                // keyword() will print the "(" if necessary
101                if (!keyword()) {
102                   sb.append(c);
103                }
104                break;
105                // decrease indentation
106             case ')':
107                indent--;
108                sb.append(c);
109                break;
110                // new line and indent
111             case ',':
112                sb.append(c + "\n");
113                indent(keywordIndent + indent * INDENT_SPACE);
114                skipspace = true;
115                break;
116                // else just print the character
117             default:
118                sb.append(c);
119          }
120       }
121       // store result
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    public static void main(String[] args) throws Exception {
171       BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
172       StringBuffer sb = new StringBuffer(" ");
173       while (br.ready()) {
174          String s = br.readLine();
175          sb.append(strip(s, null).replace('\t', ' '));
176          sb.append(" ");
177       }
178       System.out.println(sb.toString());
179       SqlPretty prettifier = new SqlPretty(sb.toString());
180       System.out.println(prettifier.toString());
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 }