001: /*
002: * DefaultStatementRunner.java
003: *
004: * This file is part of SQL Workbench/J, http://www.sql-workbench.net
005: *
006: * Copyright 2002-2008, Thomas Kellerer
007: * No part of this code maybe reused without the permission of the author
008: *
009: * To contact the author please send an email to: support@sql-workbench.net
010: *
011: */
012: package workbench.sql;
013:
014: import java.beans.PropertyChangeEvent;
015: import java.beans.PropertyChangeListener;
016: import java.sql.SQLException;
017: import java.sql.Savepoint;
018:
019: import workbench.db.DbMetadata;
020: import workbench.db.WbConnection;
021: import workbench.interfaces.Connectable;
022: import workbench.interfaces.ParameterPrompter;
023: import workbench.interfaces.ResultLogger;
024: import workbench.interfaces.StatementRunner;
025: import workbench.log.LogMgr;
026: import workbench.resource.ResourceMgr;
027: import workbench.resource.Settings;
028: import workbench.sql.wbcommands.WbEndBatch;
029: import workbench.sql.wbcommands.WbStartBatch;
030: import workbench.storage.RowActionMonitor;
031: import workbench.util.SqlUtil;
032: import workbench.interfaces.ExecutionController;
033:
034: /**
035: *
036: * @author support@sql-workbench.net
037: */
038: public class DefaultStatementRunner implements PropertyChangeListener,
039: StatementRunner {
040: private WbConnection dbConnection;
041: private Connectable connectionClient;
042: private StatementRunnerResult result;
043: private VariablePool parameterPool;
044:
045: private SqlCommand currentCommand;
046: private SqlCommand currentConsumer;
047: private String baseDir;
048:
049: private RowActionMonitor rowMonitor;
050: private ExecutionController controller;
051: private WbStartBatch batchCommand;
052: private ResultLogger resultLogger;
053: private boolean verboseLogging;
054: private boolean removeComments;
055: private boolean fullErrorReporting = false;
056: private ParameterPrompter prompter;
057: private boolean removeNewLines = false;
058: private boolean ignoreDropErrors = false;
059: protected CommandMapper cmdMapper;
060: private boolean useSavepoint;
061: private Savepoint savepoint;
062:
063: public DefaultStatementRunner() {
064: this .verboseLogging = !Settings.getInstance()
065: .getConsolidateLogMsg();
066: Settings.getInstance().addPropertyChangeListener(this ,
067: "workbench.gui.log.consolidate");
068: this .parameterPool = VariablePool.getInstance();
069: this .cmdMapper = new CommandMapper();
070: }
071:
072: public void dispose() {
073: Settings.getInstance().removePropertyChangeListener(this );
074: }
075:
076: public void propertyChange(PropertyChangeEvent evt) {
077: if ("workbench.gui.log.consolidate".equals(evt
078: .getPropertyName())) {
079: this .verboseLogging = !Settings.getInstance()
080: .getConsolidateLogMsg();
081: }
082: }
083:
084: public void setFullErrorReporting(boolean flag) {
085: this .fullErrorReporting = flag;
086: }
087:
088: public void setExecutionController(ExecutionController control) {
089: this .controller = control;
090: }
091:
092: public void setIgnoreDropErrors(boolean flag) {
093: this .ignoreDropErrors = flag;
094: }
095:
096: public boolean getIgnoreDropErrors() {
097: return this .ignoreDropErrors;
098: }
099:
100: /**
101: * For testing purposes, to that non-default commands can be added
102: * during a JUnit test
103: */
104: public void addCommand(SqlCommand command) {
105: cmdMapper.addCommand(command);
106: }
107:
108: public Connectable getConnectionClient() {
109: return this .connectionClient;
110: }
111:
112: public void setConnectionClient(Connectable client) {
113: this .connectionClient = client;
114: }
115:
116: public void setParameterPrompter(ParameterPrompter filter) {
117: this .prompter = filter;
118: }
119:
120: public void setBaseDir(String dir) {
121: this .baseDir = dir;
122: }
123:
124: public String getBaseDir() {
125: return this .baseDir;
126: }
127:
128: public WbConnection getConnection() {
129: return this .dbConnection;
130: }
131:
132: public void setConnection(WbConnection aConn) {
133: this .releaseSavepoint();
134: this .cmdMapper.setConnection(aConn);
135: this .dbConnection = aConn;
136:
137: if (aConn == null)
138: return;
139: this .ignoreDropErrors = dbConnection.getProfile()
140: .getIgnoreDropErrors();
141: this .removeComments = dbConnection.getProfile()
142: .getRemoveComments();
143:
144: DbMetadata meta = this .dbConnection.getMetadata();
145: if (meta == null)
146: return;
147:
148: // this is stored in an instance variables for performance
149: // reasons, so we can skip the call to isSelectIntoNewTable() in
150: // getCommandToUse()
151: // For a single call this doesn't matter, but when executing
152: // huge scripts the repeated call to getCommandToUse should
153: // be as quick as possible
154: this .removeNewLines = Settings.getInstance().getBoolProperty(
155: "workbench.db." + meta.getDbId() + ".removenewlines",
156: false);
157: this .useSavepoint = dbConnection.getDbSettings()
158: .useSavePointForDML();
159: }
160:
161: public StatementRunnerResult getResult() {
162: return this .result;
163: }
164:
165: public void setRowMonitor(RowActionMonitor monitor) {
166: this .rowMonitor = monitor;
167: }
168:
169: public void setResultLogger(ResultLogger logger) {
170: this .resultLogger = logger;
171: }
172:
173: public SqlCommand getCommandToUse(String sql) {
174: return this .cmdMapper.getCommandToUse(sql);
175: }
176:
177: public void runStatement(String aSql, int maxRows, int queryTimeout)
178: throws SQLException, Exception {
179: if (this .result != null) {
180: this .result.clear();
181: }
182:
183: if (this .prompter != null) {
184: boolean goOn = this .prompter.processParameterPrompts(aSql);
185: if (!goOn) {
186: this .result = new StatementRunnerResult();
187: this .result.setPromptingWasCancelled();
188: return;
189: }
190: }
191:
192: if (removeComments || removeNewLines) {
193: aSql = SqlUtil.makeCleanSql(aSql, !removeNewLines,
194: !removeComments, '\'');
195: }
196:
197: this .currentCommand = this .cmdMapper.getCommandToUse(aSql);
198:
199: if (this .currentCommand == null) {
200: this .result = null;
201: return;
202: }
203:
204: if (this .dbConnection == null
205: && this .currentCommand.isConnectionRequired()) {
206: throw new SQLException("Cannot execute command '"
207: + this .currentCommand.getVerb()
208: + " without a connection!");
209: }
210:
211: this .currentCommand
212: .setConsumerWaiting(this .currentConsumer != null);
213: this .currentCommand.setStatementRunner(this );
214: this .currentCommand.setRowMonitor(this .rowMonitor);
215: this .currentCommand.setResultLogger(this .resultLogger);
216: this .currentCommand.setMaxRows(maxRows);
217: this .currentCommand.setQueryTimeout(queryTimeout);
218: this .currentCommand.setConnection(this .dbConnection);
219: this .currentCommand.setParameterPrompter(this .prompter);
220:
221: String realSql = aSql;
222: if (parameterPool.getParameterCount() > 0) {
223: realSql = parameterPool.replaceAllParameters(aSql);
224: }
225:
226: if (this .controller != null
227: && this .currentCommand.isUpdatingCommand()) {
228: boolean doExecute = this .controller
229: .confirmExecution(realSql);
230: if (!doExecute) {
231: this .result = new StatementRunnerResult();
232: String msg = ResourceMgr
233: .getString("MsgStatementCancelled");
234: this .result.addMessage(msg);
235: this .result.setWarning(true);
236: this .result.setSuccess();
237: return;
238: }
239: }
240:
241: boolean oldReporting = this .currentCommand
242: .getFullErrorReporting();
243:
244: this .currentCommand
245: .setFullErrorReporting(this .fullErrorReporting);
246:
247: long sqlExecStart = System.currentTimeMillis();
248:
249: this .result = this .currentCommand.execute(realSql);
250:
251: this .currentCommand.setFullErrorReporting(oldReporting);
252:
253: if (this .currentCommand instanceof WbStartBatch
254: && result.isSuccess()) {
255: this .batchCommand = (WbStartBatch) this .currentCommand;
256: } else if (this .batchCommand != null
257: && this .currentCommand instanceof WbEndBatch) {
258: this .result = this .batchCommand.executeBatch();
259: } else if (this .currentCommand != null
260: && this .currentCommand.isResultSetConsumer()) {
261: this .currentConsumer = this .currentCommand;
262: } else {
263: if (this .currentConsumer != null) {
264: this .currentCommand.setConsumerWaiting(false);
265: this .currentConsumer.consumeResult(this .result);
266: this .currentConsumer = null;
267: }
268: }
269: long time = (System.currentTimeMillis() - sqlExecStart);
270: result.setExecutionTime(time);
271: }
272:
273: public void setVerboseLogging(boolean flag) {
274: this .verboseLogging = flag;
275: }
276:
277: public boolean getVerboseLogging() {
278: return this .verboseLogging;
279: }
280:
281: public void statementDone() {
282: if (this .currentCommand != null
283: && this .currentConsumer != this .currentCommand) {
284: this .currentCommand.done();
285: this .currentCommand = null;
286: }
287: }
288:
289: public void cancel() {
290: try {
291: if (this .currentConsumer != null) {
292: this .currentConsumer.cancel();
293: } else if (this .currentCommand != null) {
294: this .currentCommand.cancel();
295: }
296: } catch (Exception th) {
297: LogMgr.logWarning("StatementRunner.cancel()",
298: "Error when cancelling statement", th);
299: }
300: }
301:
302: public void done() {
303: if (this .result != null)
304: this .result.clear();
305: this .result = null;
306: this .releaseSavepoint();
307: this .statementDone();
308: this .currentConsumer = null;
309: this .dbConnection.clearWarnings();
310: }
311:
312: public void setUseSavepoint(boolean flag) {
313: this .useSavepoint = flag;
314: }
315:
316: public void setSavepoint() {
317: if (!useSavepoint)
318: return;
319: if (this .savepoint != null)
320: return;
321: try {
322: this .savepoint = this .dbConnection.setSavepoint();
323: } catch (SQLException e) {
324: LogMgr.logError("DefaultStatementRunner.setSavepoint()",
325: "Error creating savepoint", e);
326: this .savepoint = null;
327: } catch (Throwable th) {
328: LogMgr.logError("DefaultStatementRunner.setSavepoint()",
329: "Savepoints not supported!", th);
330: this .savepoint = null;
331: this .useSavepoint = false;
332: }
333: }
334:
335: public void releaseSavepoint() {
336: if (this .savepoint == null || this .dbConnection == null)
337: return;
338: try {
339: this .dbConnection.releaseSavepoint(savepoint);
340: } finally {
341: this .savepoint = null;
342: }
343: }
344:
345: public void rollbackSavepoint() {
346: if (this.savepoint == null)
347: return;
348: try {
349: this.dbConnection.rollback(savepoint);
350: } finally {
351: this.savepoint = null;
352: }
353: }
354:
355: }
|