1 package org.apache.torque.engine.sql;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.IOException;
23 import java.io.Reader;
24 import java.util.List;
25 import java.util.ArrayList;
26
27 /**
28 * A simple Scanner implementation that scans an
29 * sql file into usable tokens. Used by SQLToAppData.
30 *
31 * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
32 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
33 * @author <a href="mailto:andyhot@di.uoa.gr">Andreas Andreou</a>
34 * @version $Id: SQLScanner.java,v 1.1 2007-10-21 07:57:27 abyrne Exp $
35 */
36 public class SQLScanner
37 {
38 /** white spaces */
39 private static final String WHITE = "\f\r\t\n ";
40 /** alphabetic characters */
41 private static final String ALFA
42 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
43 /** numbers */
44 private static final String NUMER = "0123456789";
45 /** alphanumeric */
46 private static final String ALFANUM = ALFA + NUMER;
47 /** special characters */
48 private static final String SPECIAL = ";(),'";
49 /** comment */
50 private static final char COMMENT_POUND = '#';
51 /** comment */
52 private static final char COMMENT_SLASH = '/';
53 /** comment */
54 private static final char COMMENT_STAR = '*';
55 /** comment */
56 private static final char COMMENT_DASH = '-';
57
58 /** the input reader */
59 private Reader in;
60 /** character */
61 private int chr;
62 /** token */
63 private String token;
64 /** list of tokens */
65 private List tokens;
66 /** line */
67 private int line;
68 /** column */
69 private int col;
70
71 /**
72 * Creates a new scanner with no Reader
73 */
74 public SQLScanner()
75 {
76 this(null);
77 }
78
79 /**
80 * Creates a new scanner with an Input Reader
81 *
82 * @param input the input reader
83 */
84 public SQLScanner(Reader input)
85 {
86 setInput(input);
87 }
88
89 /**
90 * Set the Input
91 *
92 * @param input the input reader
93 */
94 public void setInput(Reader input)
95 {
96 in = input;
97 }
98
99
100 /**
101 * Reads the next character and increments the line and column counters.
102 *
103 * @throws IOException If an I/O error occurs
104 */
105 private void readChar() throws IOException
106 {
107 boolean wasLine = (char) chr == '\r';
108 chr = in.read();
109 if ((char) chr == '\n' || (char) chr == '\r' || (char) chr == '\f')
110 {
111 col = 0;
112 if (!wasLine || (char) chr != '\n')
113 {
114 line++;
115 }
116 }
117 else
118 {
119 col++;
120 }
121 }
122
123 /**
124 * Scans an identifier.
125 *
126 * @throws IOException If an I/O error occurs
127 */
128 private void scanIdentifier () throws IOException
129 {
130 token = "";
131 char c = (char) chr;
132 while (chr != -1 && WHITE.indexOf(c) == -1 && SPECIAL.indexOf(c) == -1)
133 {
134 token = token + (char) chr;
135 readChar();
136 c = (char) chr;
137 }
138 int start = col - token.length();
139 tokens.add(new Token(token, line, start));
140 }
141
142 /**
143 * Scans an identifier which had started with the negative sign.
144 *
145 * @throws IOException If an I/O error occurs
146 */
147 private void scanNegativeIdentifier () throws IOException
148 {
149 token = "-";
150 char c = (char) chr;
151 while (chr != -1 && WHITE.indexOf(c) == -1 && SPECIAL.indexOf(c) == -1)
152 {
153 token = token + (char) chr;
154 readChar();
155 c = (char) chr;
156 }
157 int start = col - token.length();
158 tokens.add(new Token(token, line, start));
159 }
160
161 /**
162 * Scan the input Reader and returns a list of tokens.
163 *
164 * @return a list of tokens
165 * @throws IOException If an I/O error occurs
166 */
167 public List scan () throws IOException
168 {
169 line = 1;
170 col = 0;
171 boolean inComment = false;
172 boolean inCommentSlashStar = false;
173 boolean inCommentDash = false;
174
175 boolean inNegative;
176
177 tokens = new ArrayList();
178 readChar();
179 while (chr != -1)
180 {
181 char c = (char) chr;
182 inNegative = false;
183
184 if (c == COMMENT_DASH)
185 {
186 readChar();
187 if ((char) chr == COMMENT_DASH)
188 {
189 inCommentDash = true;
190 }
191 else
192 {
193 inNegative = true;
194 c = (char) chr;
195 }
196 }
197
198 if (inCommentDash)
199 {
200 if (c == '\n' || c == '\r')
201 {
202 inCommentDash = false;
203 }
204 readChar();
205 }
206 else if (c == COMMENT_POUND)
207 {
208 inComment = true;
209 readChar();
210 }
211 else if (c == COMMENT_SLASH)
212 {
213 readChar();
214 if ((char) chr == COMMENT_STAR)
215 {
216 inCommentSlashStar = true;
217 }
218 }
219 else if (inComment || inCommentSlashStar)
220 {
221 if (c == '*')
222 {
223 readChar();
224 if ((char) chr == COMMENT_SLASH)
225 {
226 inCommentSlashStar = false;
227 }
228 }
229 else if (c == '\n' || c == '\r')
230 {
231 inComment = false;
232 }
233 readChar();
234 }
235 else if (ALFANUM.indexOf(c) >= 0)
236 {
237 if (inNegative)
238 {
239 scanNegativeIdentifier();
240 }
241 else
242 {
243 scanIdentifier();
244 }
245 }
246 else if (SPECIAL.indexOf(c) >= 0)
247 {
248 tokens.add(new Token("" + c, line, col));
249 readChar();
250 }
251 else
252 {
253 readChar();
254 }
255 }
256 return tokens;
257 }
258 }