1 19 20 package org.netbeans.modules.db.sql.execute; 21 22 import java.sql.Connection ; 23 import java.sql.DatabaseMetaData ; 24 import java.sql.PreparedStatement ; 25 import java.sql.ResultSet ; 26 import java.sql.SQLException ; 27 import java.sql.Statement ; 28 import java.util.ArrayList ; 29 import java.util.Collections ; 30 import java.util.Iterator ; 31 import java.util.List ; 32 import org.netbeans.api.progress.ProgressHandle; 33 import org.openide.ErrorManager; 34 35 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 52 public static SQLExecutionResults execute(String sqlScript, int startOffset, int endOffset, Connection conn, ProgressHandle progressHandle, SQLExecutionLogger executionLogger) { 53 54 boolean cancelled = false; 55 56 List <StatementInfo> statements = getStatements(sqlScript, startOffset, endOffset); 57 boolean computeResults = statements.size() == 1; 58 59 List <SQLExecutionResult> resultList = new ArrayList <SQLExecutionResult>(); 60 long totalExecutionTime = 0; 61 62 for (Iterator 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 sql = info.getSQL(); 71 72 if (LOG) { 73 LOGGER.log(ErrorManager.INFORMATIONAL, "Executing: " + sql); } 75 76 SQLExecutionResult result = null; 77 Statement stmt = null; 78 79 try { 80 if (sql.startsWith("{")) { 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 ) { 89 isResultSet = ((PreparedStatement )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 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); } 111 112 if (computeResults || result.getException() != null) { 113 resultList.add(result); 114 } else { 115 try { 116 result.close(); 117 } catch (SQLException 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"); } 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 conn) throws SQLException { 142 145 DatabaseMetaData 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 <StatementInfo> getStatements(String script, int startOffset, int endOffset) { 159 List <StatementInfo> allStatements = split(script); 160 if (startOffset == 0 && endOffset == script.length()) { 161 return allStatements; 162 } 163 List <StatementInfo> statements = new ArrayList <StatementInfo>(); 164 for (Iterator i = allStatements.iterator(); i.hasNext();) { 165 StatementInfo stmt = (StatementInfo)i.next(); 166 if (startOffset == endOffset) { 167 if (stmt.getStartOffset() <= startOffset && stmt.getEndOffset() >= endOffset) { 169 statements.add(stmt); 170 } 171 } else { 172 if (stmt.getStartOffset() >= startOffset && stmt.getEndOffset() <= endOffset) { 174 statements.add(stmt); 175 } 176 } 177 } 178 return Collections.unmodifiableList(statements); 179 } 180 181 static List <StatementInfo> split(String 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 sql; 196 private int sqlLength; 197 198 private StringBuffer statement = new StringBuffer (); 199 private List <StatementInfo> statements = new ArrayList <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 217 public SQLSplitter(String 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') { if (LOG) { 231 LOGGER.log(ErrorManager.INFORMATIONAL, "The SQL string contained non-supported \r characters."); } 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('-'); endOffset = pos; 268 } 269 break; 270 271 case STATE_LINE_COMMENT: 272 if (ch == '\n') { 273 state = STATE_START; 274 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('/'); 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 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 if (statement.length() > 0 || !Character.isWhitespace(ch)) { 326 if (statement.length() == 0) { 328 startOffset = pos; 329 endOffset = pos; 330 startLine = line; 331 startColumn = column; 332 } 333 statement.append(ch); 334 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 String 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 <StatementInfo> getStatements() { 362 return Collections.unmodifiableList(statements); 363 } 364 } 365 } 366 | Popular Tags |