KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > db > sql > execute > SQLExecuteHelper


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.db.sql.execute;
21
22 import java.sql.Connection JavaDoc;
23 import java.sql.DatabaseMetaData JavaDoc;
24 import java.sql.PreparedStatement JavaDoc;
25 import java.sql.ResultSet JavaDoc;
26 import java.sql.SQLException JavaDoc;
27 import java.sql.Statement JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Collections JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.List JavaDoc;
32 import org.netbeans.api.progress.ProgressHandle;
33 import org.openide.ErrorManager;
34
35 /**
36  * Support class for executing SQL statements.
37  *
38  * @author Andrei Badea
39  */

40 public final class SQLExecuteHelper {
41
42     private static final ErrorManager LOGGER = ErrorManager.getDefault().getInstance(SQLExecuteHelper.class.getName());
43     private static final boolean LOG = LOGGER.isLoggable(ErrorManager.INFORMATIONAL);
44     
45     /**
46      * Executes a SQL string, possibly containing multiple statements. Returns the execution
47      * result, but only if the string contained a single statement.
48      *
49      * @param sqlScript the SQL script to execute. If it contains multiple lines
50      * they have to be delimited by '\n' characters.
51      */

52     public static SQLExecutionResults execute(String JavaDoc sqlScript, int startOffset, int endOffset, Connection JavaDoc conn, ProgressHandle progressHandle, SQLExecutionLogger executionLogger) {
53         
54         boolean cancelled = false;
55         
56         List JavaDoc<StatementInfo> statements = getStatements(sqlScript, startOffset, endOffset);
57         boolean computeResults = statements.size() == 1;
58         
59         List JavaDoc<SQLExecutionResult> resultList = new ArrayList JavaDoc<SQLExecutionResult>();
60         long totalExecutionTime = 0;
61         
62         for (Iterator JavaDoc i = statements.iterator(); i.hasNext();) {
63             
64             cancelled = Thread.currentThread().isInterrupted();
65             if (cancelled) {
66                 break;
67             }
68             
69             StatementInfo info = (StatementInfo)i.next();
70             String JavaDoc sql = info.getSQL();
71             
72             if (LOG) {
73                 LOGGER.log(ErrorManager.INFORMATIONAL, "Executing: " + sql); // NOI18N
74
}
75             
76             SQLExecutionResult result = null;
77             Statement JavaDoc stmt = null;
78             
79             try {
80                 if (sql.startsWith("{")) { // NOI18N
81
stmt = conn.prepareCall(sql);
82                 } else {
83                     stmt = conn.createStatement();
84                 }
85                 
86                 boolean isResultSet = false;
87                 long startTime = System.currentTimeMillis();
88                 if (stmt instanceof PreparedStatement JavaDoc) {
89                     isResultSet = ((PreparedStatement JavaDoc)stmt).execute();
90                 } else {
91                     isResultSet = stmt.execute(sql);
92                 }
93                 long executionTime = System.currentTimeMillis() - startTime;
94                 totalExecutionTime += executionTime;
95                 
96                 if (isResultSet) {
97                     result = new SQLExecutionResult(info, stmt, stmt.getResultSet(), executionTime);
98                 } else {
99                     result = new SQLExecutionResult(info, stmt, stmt.getUpdateCount(), executionTime);
100                 }
101             } catch (SQLException JavaDoc e) {
102                 result = new SQLExecutionResult(info, stmt, e);
103             }
104             assert result != null;
105             
106             executionLogger.log(result);
107             
108             if (LOG) {
109                 LOGGER.log(ErrorManager.INFORMATIONAL, "Result: " + result); // NOI18N
110
}
111             
112             if (computeResults || result.getException() != null) {
113                 resultList.add(result);
114             } else {
115                 try {
116                     result.close();
117                 } catch (SQLException JavaDoc e) {
118                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
119                 }
120             }
121         }
122         
123         if (!cancelled) {
124             executionLogger.finish(totalExecutionTime);
125         } else {
126             if (LOG) {
127                 LOGGER.log(ErrorManager.INFORMATIONAL, "Execution cancelled"); // NOI18N
128
}
129             executionLogger.cancel();
130         }
131         
132         SQLExecutionResults results = new SQLExecutionResults(resultList);
133         if (!cancelled) {
134             return results;
135         } else {
136             results.close();
137             return null;
138         }
139     }
140     
141     private static int[] getSupportedResultSetTypeConcurrency(Connection JavaDoc conn) throws SQLException JavaDoc {
142         // XXX some drivers don't implement the DMD.supportsResultSetConcurrency() method
143
// for example the MSSQL WebLogic driver 4v70rel510 always throws AbstractMethodError
144

145         DatabaseMetaData JavaDoc dmd = conn.getMetaData();
146         
147         int type = ResultSet.TYPE_SCROLL_INSENSITIVE;
148         int concurrency = ResultSet.CONCUR_UPDATABLE;
149         if (!dmd.supportsResultSetConcurrency(type, concurrency)) {
150             concurrency = ResultSet.CONCUR_READ_ONLY;
151             if (!dmd.supportsResultSetConcurrency(type, concurrency)) {
152                 type = ResultSet.TYPE_FORWARD_ONLY;
153             }
154         }
155         return new int[] { type, concurrency };
156     }
157     
158     private static List JavaDoc<StatementInfo> getStatements(String JavaDoc script, int startOffset, int endOffset) {
159         List JavaDoc<StatementInfo> allStatements = split(script);
160         if (startOffset == 0 && endOffset == script.length()) {
161             return allStatements;
162         }
163         List JavaDoc<StatementInfo> statements = new ArrayList JavaDoc<StatementInfo>();
164         for (Iterator JavaDoc i = allStatements.iterator(); i.hasNext();) {
165             StatementInfo stmt = (StatementInfo)i.next();
166             if (startOffset == endOffset) {
167                 // only find the statement at offset startOffset
168
if (stmt.getStartOffset() <= startOffset && stmt.getEndOffset() >= endOffset) {
169                     statements.add(stmt);
170                 }
171             } else {
172                 // find the statements between startOffset and endOffset
173
if (stmt.getStartOffset() >= startOffset && stmt.getEndOffset() <= endOffset) {
174                     statements.add(stmt);
175                 }
176             }
177         }
178         return Collections.unmodifiableList(statements);
179     }
180     
181     static List JavaDoc<StatementInfo> split(String JavaDoc script) {
182         return new SQLSplitter(script).getStatements();
183     }
184     
185     private static final class SQLSplitter {
186         
187         private static final int STATE_START = 0;
188         private static final int STATE_MAYBE_LINE_COMMENT = 1;
189         private static final int STATE_LINE_COMMENT = 2;
190         private static final int STATE_MAYBE_BLOCK_COMMENT = 3;
191         private static final int STATE_BLOCK_COMMENT = 4;
192         private static final int STATE_MAYBE_END_BLOCK_COMMENT = 5;
193         private static final int STATE_STRING = 6;
194         
195         private String JavaDoc sql;
196         private int sqlLength;
197         
198         private StringBuffer JavaDoc statement = new StringBuffer JavaDoc();
199         private List JavaDoc<StatementInfo> statements = new ArrayList JavaDoc<StatementInfo>();
200         
201         private int pos = 0;
202         private int line = -1;
203         private int column;
204         private boolean wasEOL = true;
205         
206         private int startOffset;
207         private int startLine;
208         private int startColumn;
209         private int endOffset;
210         
211         private int state = STATE_START;
212         
213         /**
214          * @param sql the SQL string to parse. If it contains multiple lines
215          * they have to be delimited by '\n' characters.
216          */

217         public SQLSplitter(String JavaDoc sql) {
218             assert sql != null;
219             this.sql = sql;
220             sqlLength = sql.length();
221             parse();
222         }
223         
224         private void parse() {
225             while (pos < sqlLength) {
226                 char ch = sql.charAt(pos);
227                 
228                 if (ch == '\r') { // NOI18N
229
// the string should not contain these
230
if (LOG) {
231                         LOGGER.log(ErrorManager.INFORMATIONAL, "The SQL string contained non-supported \r characters."); // NOI18N
232
}
233                     continue;
234                 }
235                 
236                 if (wasEOL) {
237                     line++;
238                     column = 0;
239                     wasEOL = false;
240                 } else {
241                     column++;
242                 }
243                 
244                 if (ch == '\n') {
245                     wasEOL = true;
246                 }
247                 
248                 switch (state) {
249                     case STATE_START:
250                         if (ch == '-') {
251                             state = STATE_MAYBE_LINE_COMMENT;
252                         }
253                         if (ch == '/') {
254                             state = STATE_MAYBE_BLOCK_COMMENT;
255                         }
256                         if (ch == '\'') {
257                             state = STATE_STRING;
258                         }
259                         break;
260                         
261                     case STATE_MAYBE_LINE_COMMENT:
262                         if (ch == '-') {
263                             state = STATE_LINE_COMMENT;
264                         } else {
265                             state = STATE_START;
266                             statement.append('-'); // previous char
267
endOffset = pos;
268                         }
269                         break;
270                         
271                     case STATE_LINE_COMMENT:
272                         if (ch == '\n') {
273                             state = STATE_START;
274                             // avoid appending the final \n to the result
275
pos++;
276                             continue;
277                         }
278                         break;
279                         
280                     case STATE_MAYBE_BLOCK_COMMENT:
281                         if (ch == '*') {
282                             state = STATE_BLOCK_COMMENT;
283                         } else {
284                             statement.append('/'); // previous char
285
endOffset = pos;
286                             if (ch != '/') {
287                                 state = STATE_START;
288                             }
289                         }
290                         break;
291                         
292                     case STATE_BLOCK_COMMENT:
293                         if (ch == '*') {
294                             state = STATE_MAYBE_END_BLOCK_COMMENT;
295                         }
296                         break;
297                         
298                     case STATE_MAYBE_END_BLOCK_COMMENT:
299                         if (ch == '/') {
300                             state = STATE_START;
301                             // avoid writing the final / to the result
302
pos++;
303                             continue;
304                         } else if (ch != '*') {
305                             state = STATE_BLOCK_COMMENT;
306                         }
307                         break;
308                         
309                     case STATE_STRING:
310                         if (ch == '\n' || ch == '\'') {
311                             state = STATE_START;
312                         }
313                         break;
314                         
315                     default:
316                         assert false;
317                 }
318                 
319                 if (state == STATE_START && ch == ';') {
320                     addStatement();
321                     statement.setLength(0);
322                 } else {
323                     if (state == STATE_START || state == STATE_STRING) {
324                         // don't append leading whitespace
325
if (statement.length() > 0 || !Character.isWhitespace(ch)) {
326                             // remember the position of the first appended char
327
if (statement.length() == 0) {
328                                 startOffset = pos;
329                                 endOffset = pos;
330                                 startLine = line;
331                                 startColumn = column;
332                             }
333                             statement.append(ch);
334                             // the end offset is the character after the last non-whitespace character
335
if (state == STATE_STRING || !Character.isWhitespace(ch)) {
336                                 endOffset = pos + 1;
337                             }
338                         }
339                     }
340                 }
341                 
342                 pos++;
343             }
344             
345             addStatement();
346         }
347         
348         private void addStatement() {
349             // PENDING since startOffset is the first non-whitespace char and
350
// endOffset is the offset after the last non-whitespace char,
351
// the trim() call could be replaced with statement.substring(startOffset, endOffset)
352
String JavaDoc sql = statement.toString().trim();
353             if (sql.length() <= 0) {
354                 return;
355             }
356             
357             StatementInfo info = new StatementInfo(sql, startOffset, startLine, startColumn, endOffset);
358             statements.add(info);
359         }
360         
361         public List JavaDoc<StatementInfo> getStatements() {
362             return Collections.unmodifiableList(statements);
363         }
364     }
365 }
366
Popular Tags