001: package com.quadcap.app.bugdb;
002:
003: /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.BufferedInputStream;
042: import java.io.File;
043: import java.io.FileInputStream;
044: import java.io.IOException;
045: import java.io.InputStream;
046: import java.io.PrintWriter;
047:
048: import java.sql.Connection;
049: import java.sql.DriverManager;
050: import java.sql.ResultSet;
051: import java.sql.ResultSetMetaData;
052: import java.sql.SQLException;
053: import java.sql.Statement;
054:
055: /**
056: * A simple SQL loader utility.
057: *
058: * @author Stan Bailes
059: */
060: public class Loader {
061: Connection conn;
062: StringBuffer buffer = new StringBuffer();
063: PrintWriter writer = null;
064:
065: /**
066: * Construct a new loader. It needs a connection in order to do
067: * anything useful.
068: */
069: public Loader() {
070: }
071:
072: /**
073: * Construct a new loader bound to the specified connection.
074: *
075: * @param conn the connection to use.
076: */
077: public Loader(Connection conn) {
078: this .conn = conn;
079: }
080:
081: /**
082: * Set the loader's connection
083: *
084: * @param conn the connection to use.
085: */
086: public void setConnection(Connection conn) {
087: this .conn = conn;
088: }
089:
090: /**
091: * Get the loaders's connection
092: *
093: * @return the loader's current connection
094: */
095: public Connection getConnection() {
096: return this .conn;
097: }
098:
099: /**
100: * Get the PrintWriter used to display the results of select statements.
101: *
102: * @return the current writer
103: */
104: public PrintWriter getWriter() {
105: return writer;
106: }
107:
108: /**
109: * Set the PrintWriter used to display the results of select statements.
110: *
111: * @param writer the new writer
112: */
113: public void setWriter(PrintWriter writer) {
114: this .writer = writer;
115: }
116:
117: /**
118: * Print (if a writer is set) the specified string
119: *
120: * @param s the string
121: */
122: final void print(String s) {
123: if (writer != null)
124: writer.print(s);
125: }
126:
127: /**
128: * Print (if a writer is set) the specified string,
129: * with a trailing newline.
130: *
131: * @param s the string
132: */
133: final void println(String s) {
134: if (writer != null)
135: writer.println(s);
136: }
137:
138: /**
139: * Print (if a writer is set) the stack trace for the specified throwable.
140: *
141: * @param t the throwable
142: */
143: final void print(Throwable t) {
144: if (writer != null)
145: t.printStackTrace(writer);
146: if (t instanceof SQLException) {
147: SQLException e = ((SQLException) t).getNextException();
148: if (e != null) {
149: print(e);
150: }
151: }
152: }
153:
154: /**
155: * Return a string left-justified in a field 'wid' characters wide.
156: *
157: * @param wid the field width
158: * @param s the input string
159: * @return the padded string
160: */
161: final static String pad(int wid, String s) {
162: StringBuffer sb = new StringBuffer(s);
163: while (sb.length() < wid)
164: sb.append(' ');
165: return sb.toString();
166: }
167:
168: /**
169: * Display a result set (to the current writer)
170: *
171: * @param rs the result set
172: * @exception SQLException may be thrown
173: */
174: final void showResultSet(ResultSet rs) throws SQLException {
175: ResultSetMetaData rmeta = rs.getMetaData();
176: String delim = "";
177: for (int i = 1; i <= rmeta.getColumnCount(); i++) {
178: int wid = rmeta.getColumnDisplaySize(i);
179: if (wid > 32)
180: wid = 32;
181: print(delim);
182: delim = " ";
183: print(pad(wid, rmeta.getColumnName(i)));
184: }
185: println("");
186: while (rs.next()) {
187: delim = "";
188: for (int i = 1; i <= rmeta.getColumnCount(); i++) {
189: int wid = rmeta.getColumnDisplaySize(i);
190: if (wid > 32)
191: wid = 32;
192: print(delim);
193: delim = " ";
194: Object obj = rs.getObject(i);
195: if (obj == null)
196: obj = "<null>";
197: if (obj instanceof byte[]) {
198: obj = hexBytes((byte[]) obj);
199: }
200: print(pad(wid, obj.toString()));
201: }
202: println("");
203: }
204: }
205:
206: /**
207: * Return the next SQL command from the input stream.
208: *
209: * @param is the input stream
210: * @return the SQL statement
211: * @exception IOException may be thrown
212: */
213: static String getLine(InputStream is) throws IOException {
214: StringBuffer sb = new StringBuffer();
215: int ch;
216: int state = 0;
217: while ((ch = is.read()) > 0) {
218: char c = (char) ch;
219: switch (state) {
220: case 0:
221: if (c == '-') {
222: state = 1;
223: } else if (c == ';') {
224: if (sb.length() > 0) {
225: return sb.toString();
226: }
227: } else if (Character.isWhitespace(c)
228: && sb.length() == 0) {
229: } else {
230: sb.append(c);
231: }
232: break;
233: case 1:
234: if (c == '-') {
235: state = 2;
236: } else {
237: sb.append('-');
238: sb.append(c);
239: state = 0;
240: }
241: break;
242: case 2:
243: if (c == '\r')
244: state = 3;
245: if (c == '\n')
246: state = 0;
247: break;
248: case 3:
249: if (c == '\n')
250: state = 0;
251: break;
252: }
253: }
254: return null;
255: }
256:
257: /**
258: * Execute the specified SQL command
259: *
260: * @param sql the SQL statement to execute
261: */
262: final void execute(String sql) {
263: try {
264: Statement stmt = conn.createStatement();
265: try {
266: if (sql.equals("BEGINTRANSACTION")) {
267: conn.setAutoCommit(false);
268: } else if (sql.equals("ENDTRANSACTION")
269: || sql.equals("COMMIT")) {
270: conn.commit();
271: conn.setAutoCommit(true);
272: } else if (sql.equals("ROLLBACK")) {
273: conn.rollback();
274: conn.setAutoCommit(true);
275: } else {
276: if (stmt.execute(sql)) {
277: ResultSet rs = stmt.getResultSet();
278: try {
279: showResultSet(rs);
280: } finally {
281: rs.close();
282: }
283: }
284: }
285: } catch (Throwable t) {
286: print(t);
287: } finally {
288: stmt.close();
289: }
290: } catch (Throwable t) {
291: print(t);
292: }
293: }
294:
295: /**
296: * The main point of this class, which is to execute all the SQL commands
297: * found in the specified file.
298: *
299: * @param filename the name of the file
300: */
301: public void loadFile(String filename) throws IOException {
302: FileInputStream fis = new FileInputStream(filename);
303: loadStream(fis);
304: }
305:
306: /**
307: * Execute the SQL script contained in the specified input stream
308: *
309: * @param is the input stream
310: */
311: public void loadStream(InputStream is) {
312: try {
313: Statement stmt = conn.createStatement();
314: BufferedInputStream bis = new BufferedInputStream(is, 1024);
315: String sql = null;
316: while ((sql = getLine(bis)) != null) {
317: try {
318: if (sql.equals("BEGINTRANSACTION")) {
319: conn.setAutoCommit(false);
320: } else if (sql.equals("ENDTRANSACTION")
321: || sql.equals("COMMIT")) {
322: conn.commit();
323: conn.setAutoCommit(true);
324: } else if (sql.equals("ROLLBACK")) {
325: conn.rollback();
326: conn.setAutoCommit(true);
327: } else {
328: if (stmt.execute(sql)) {
329: ResultSet rs = stmt.getResultSet();
330: showResultSet(rs);
331: }
332: }
333: } catch (Throwable t) {
334: print(t);
335: }
336: }
337: } catch (Throwable t) {
338: print(t);
339: } finally {
340: try {
341: is.close();
342: } catch (Exception e) {
343: }
344: }
345: }
346:
347: static char[] hexMap = { '0', '1', '2', '3', '4', '5', '6', '7',
348: '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
349:
350: /**
351: * Return a string containing the hexadecimal representation of the
352: * specified byte array
353: *
354: * @param buf the byte array
355: * @return the ASCII hex representation of the byte array.
356: */
357: public static String hexBytes(byte[] buf) {
358: if (buf == null)
359: return "<null>";
360: return hexBytes(buf, 0, buf.length);
361: }
362:
363: /**
364: * Return a string containing the hexadecimal representation of
365: * a portion of the specified byte array
366: *
367: * @param buf the byte array
368: * @param off the position of the first byte to convert
369: * @param len the number of bytes to convert
370: * @return the ASCII hex representation of the bytes
371: */
372: public static String hexBytes(byte[] buf, int off, int len) {
373: if (buf == null)
374: return "<null>";
375: StringBuffer sb = new StringBuffer();
376: for (int i = off; i < off + len; i++) {
377: byte b = buf[i];
378: sb.append(hexMap[(b >> 4) & 0xf]);
379: sb.append(hexMap[b & 0xf]);
380: }
381: return sb.toString();
382: }
383: }
|