[#1177] Add SQL Console module to jOOQ - Code refactored to allow
evolutions (breakpoints, remote execution, filters, etc.)
This commit is contained in:
parent
bb12708eb9
commit
fbe09689d0
@ -121,10 +121,21 @@ public class DebugListener extends DefaultExecuteListener {
|
||||
return;
|
||||
}
|
||||
endExecutionTime = System.currentTimeMillis();
|
||||
List<Debugger> sqlQueryDebuggerList = DebuggerRegistry.getDebuggerList();
|
||||
if(sqlQueryDebuggerList.isEmpty()) {
|
||||
List<Debugger> debuggerList = DebuggerRegistry.getDebuggerList();
|
||||
if(debuggerList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
boolean hasListener = false;
|
||||
for(Debugger listener: debuggerList) {
|
||||
LoggingListener loggingListener = listener.getLoggingListener();
|
||||
if(loggingListener != null) {
|
||||
hasListener = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!hasListener) {
|
||||
return;
|
||||
}
|
||||
ResultSet resultSet = ctx.resultSet();
|
||||
String[] sql = ctx.batchSQL();
|
||||
SqlQueryType sqlQueryType = SqlQueryType.detectType(sql[0]);
|
||||
@ -135,22 +146,31 @@ public class DebugListener extends DefaultExecuteListener {
|
||||
parameterDescription = ((UsageTrackingPreparedStatement) statement).getParameterDescription();
|
||||
}
|
||||
}
|
||||
DebuggerData sqlQueryDebuggerData = new DebuggerData(sqlQueryType, sql, parameterDescription, startPreparationTime == 0? null: aggregatedPreparationDuration, startBindTime == 0? null: endBindTime - startBindTime, endExecutionTime - startExecutionTime);
|
||||
for(Debugger listener: sqlQueryDebuggerList) {
|
||||
listener.debugQueries(sqlQueryDebuggerData);
|
||||
QueryLoggingData queryLoggingData = new QueryLoggingData(sqlQueryType, sql, parameterDescription, startPreparationTime == 0? null: aggregatedPreparationDuration, startBindTime == 0? null: endBindTime - startBindTime, endExecutionTime - startExecutionTime);
|
||||
for(Debugger listener: debuggerList) {
|
||||
LoggingListener loggingListener = listener.getLoggingListener();
|
||||
if(loggingListener != null) {
|
||||
loggingListener.logQueries(queryLoggingData);
|
||||
}
|
||||
}
|
||||
if(resultSet != null) {
|
||||
final int sqlQueryDebuggerDataID = sqlQueryDebuggerData.getID();
|
||||
final int queryLoggingDataID = queryLoggingData.getID();
|
||||
ResultSet newResultSet = new UsageTrackingResultSet(resultSet) {
|
||||
@Override
|
||||
protected void notifyData(long lifeTime, int readRows, int readCount, int writeCount) {
|
||||
List<Debugger> sqlQueryDebuggerList = DebuggerRegistry.getDebuggerList();
|
||||
if(sqlQueryDebuggerList.isEmpty()) {
|
||||
List<Debugger> debuggerList = DebuggerRegistry.getDebuggerList();
|
||||
if(debuggerList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
DebuggerResultSetData sqlQueryDebuggerResultSetData = new DebuggerResultSetData(lifeTime, readRows, readCount, writeCount);
|
||||
for(Debugger listener: sqlQueryDebuggerList) {
|
||||
listener.debugResultSet(sqlQueryDebuggerDataID, sqlQueryDebuggerResultSetData);
|
||||
ResultSetLoggingData resultSetLoggingData = null;
|
||||
for(Debugger debugger: debuggerList) {
|
||||
LoggingListener loggingListener = debugger.getLoggingListener();
|
||||
if(loggingListener != null) {
|
||||
if(resultSetLoggingData == null) {
|
||||
resultSetLoggingData = new ResultSetLoggingData(lifeTime, readRows, readCount, writeCount);
|
||||
}
|
||||
loggingListener.logResultSet(queryLoggingDataID, resultSetLoggingData);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,49 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* Christopher Deckers, chrriis@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.debug;
|
||||
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public interface Debugger {
|
||||
|
||||
public void debugQueries(DebuggerData sqlQueryDebuggerData);
|
||||
|
||||
public void debugResultSet(int sqlQueryDebuggerDataID, DebuggerResultSetData sqlQueryDebuggerResultSetData);
|
||||
|
||||
}
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* Christopher Deckers, chrriis@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.debug;
|
||||
|
||||
|
||||
|
||||
public interface Debugger {
|
||||
|
||||
public void setLoggingListener(LoggingListener loggingListener);
|
||||
|
||||
public LoggingListener getLoggingListener();
|
||||
|
||||
public boolean isExecutionSupported();
|
||||
|
||||
public StatementExecutor createStatementExecutor(String sql, int maxRSRowsParsing, int retainParsedRSDataRowCountThreshold);
|
||||
|
||||
public String[] getTableNames();
|
||||
|
||||
public String[] getTableColumnNames();
|
||||
|
||||
public boolean isReadOnly();
|
||||
|
||||
}
|
||||
|
||||
@ -40,6 +40,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@ -53,32 +54,12 @@ public class DebuggerRegistry {
|
||||
public static void addSqlQueryDebugger(Debugger sqlQueryDebugger) {
|
||||
synchronized(LOCK) {
|
||||
debuggerList.add(sqlQueryDebugger);
|
||||
for(DebuggerRegistryListener l: debuggerRegisterListenerList) {
|
||||
l.notifyDebuggerListenersModified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeSqlQueryDebugger(Debugger sqlQueryDebugger) {
|
||||
synchronized(LOCK) {
|
||||
debuggerList.remove(sqlQueryDebugger);
|
||||
for(DebuggerRegistryListener l: debuggerRegisterListenerList) {
|
||||
l.notifyDebuggerListenersModified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final List<DebuggerRegistryListener> debuggerRegisterListenerList = new ArrayList<DebuggerRegistryListener>(1);
|
||||
|
||||
public static void addDebuggerRegisterListener(DebuggerRegistryListener listener) {
|
||||
synchronized(LOCK) {
|
||||
debuggerRegisterListenerList.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeDebuggerRegisterListener(DebuggerRegistryListener listener) {
|
||||
synchronized(LOCK) {
|
||||
debuggerRegisterListenerList.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
113
jOOQ-console/src/main/java/org/jooq/debug/LocalDebugger.java
Normal file
113
jOOQ-console/src/main/java/org/jooq/debug/LocalDebugger.java
Normal file
@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* Christopher Deckers, chrriis@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.debug;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.debug.console.DatabaseDescriptor;
|
||||
|
||||
|
||||
public class LocalDebugger implements Debugger {
|
||||
|
||||
private DatabaseDescriptor databaseDescriptor;
|
||||
|
||||
public LocalDebugger(DatabaseDescriptor databaseDescriptor) {
|
||||
this.databaseDescriptor = databaseDescriptor;
|
||||
}
|
||||
|
||||
private LoggingListener loggingListener;
|
||||
|
||||
@Override
|
||||
public void setLoggingListener(LoggingListener loggingListener) {
|
||||
this.loggingListener = loggingListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoggingListener getLoggingListener() {
|
||||
return loggingListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExecutionSupported() {
|
||||
return databaseDescriptor != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementExecutor createStatementExecutor(String sql, int maxRSRowsParsing, int retainParsedRSDataRowCountThreshold) {
|
||||
return new StatementExecutorImpl(databaseDescriptor, sql, maxRSRowsParsing, retainParsedRSDataRowCountThreshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTableNames() {
|
||||
List<Table<?>> tableList = databaseDescriptor.getSchema().getTables();
|
||||
List<String> tableNameList = new ArrayList<String>();
|
||||
for(Table<? extends Record> table: tableList) {
|
||||
String tableName = table.getName();
|
||||
tableNameList.add(tableName);
|
||||
}
|
||||
Collections.sort(tableNameList, String.CASE_INSENSITIVE_ORDER);
|
||||
return tableNameList.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTableColumnNames() {
|
||||
Set<String> columnNameSet = new HashSet<String>();
|
||||
for(Table<?> table: databaseDescriptor.getSchema().getTables()) {
|
||||
for(Field<?> field: table.getFields()) {
|
||||
String columnName = field.getName();
|
||||
columnNameSet.add(columnName);
|
||||
}
|
||||
}
|
||||
String[] columnNames = columnNameSet.toArray(new String[0]);
|
||||
Arrays.sort(columnNames, String.CASE_INSENSITIVE_ORDER);
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return databaseDescriptor.isReadOnly();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* Christopher Deckers, chrriis@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.debug;
|
||||
|
||||
|
||||
public interface LoggingListener {
|
||||
|
||||
public void logQueries(QueryLoggingData queryLoggingData);
|
||||
|
||||
public void logResultSet(int queryLoggingDataID, ResultSetLoggingData sqlQueryDebuggerResultSetData);
|
||||
|
||||
}
|
||||
@ -42,7 +42,7 @@ import java.io.Serializable;
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class DebuggerData implements Serializable {
|
||||
public class QueryLoggingData implements Serializable {
|
||||
|
||||
private static volatile int nextID;
|
||||
|
||||
@ -57,7 +57,7 @@ public class DebuggerData implements Serializable {
|
||||
private long threadID;
|
||||
private StackTraceElement[] callerStackTraceElements;
|
||||
|
||||
public DebuggerData(SqlQueryType queryType, String[] queries, String parameterDescription, Long preparationDuration, Long bindingDuration, long executionDuration) {
|
||||
public QueryLoggingData(SqlQueryType queryType, String[] queries, String parameterDescription, Long preparationDuration, Long bindingDuration, long executionDuration) {
|
||||
this.id = nextID++;
|
||||
Thread currentThread = Thread.currentThread();
|
||||
this.threadName = currentThread.getName();
|
||||
@ -41,7 +41,7 @@ import java.io.Serializable;
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class DebuggerResultSetData implements Serializable {
|
||||
public class ResultSetLoggingData implements Serializable {
|
||||
|
||||
private static volatile int nextID;
|
||||
|
||||
@ -51,7 +51,7 @@ public class DebuggerResultSetData implements Serializable {
|
||||
private final int readCount;
|
||||
private final int writeCount;
|
||||
|
||||
public DebuggerResultSetData(long lifeTime, final int readRows, final int readCount, final int writeCount) {
|
||||
public ResultSetLoggingData(long lifeTime, final int readRows, final int readCount, final int writeCount) {
|
||||
this.id = nextID++;
|
||||
this.lifeTime = lifeTime;
|
||||
this.readRows = readRows;
|
||||
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* Christopher Deckers, chrriis@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.debug;
|
||||
|
||||
|
||||
|
||||
public class StatementExecution {
|
||||
|
||||
private long executionDuration;
|
||||
|
||||
private StatementExecutionResult[] results;
|
||||
|
||||
public StatementExecution(long executionDuration, StatementExecutionResult... results) {
|
||||
this.executionDuration = executionDuration;
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
public StatementExecutionResult[] getResults() {
|
||||
return results;
|
||||
}
|
||||
|
||||
public long getExecutionDuration() {
|
||||
return executionDuration;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* Christopher Deckers, chrriis@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.debug;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
public class StatementExecutionMessageResult implements StatementExecutionResult {
|
||||
|
||||
private String message;
|
||||
private boolean isError;
|
||||
|
||||
public StatementExecutionMessageResult(String message, boolean isError) {
|
||||
this.message = message;
|
||||
this.isError = isError;
|
||||
}
|
||||
|
||||
public StatementExecutionMessageResult(Exception e) {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(stringWriter));
|
||||
this.message = stringWriter.toString();
|
||||
isError = true;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return isError;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,43 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* Christopher Deckers, chrriis@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.debug;
|
||||
|
||||
public interface DebuggerRegistryListener {
|
||||
|
||||
public void notifyDebuggerListenersModified();
|
||||
|
||||
}
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* Christopher Deckers, chrriis@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.debug;
|
||||
|
||||
|
||||
public interface StatementExecutionResult {
|
||||
|
||||
}
|
||||
@ -0,0 +1,177 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* Christopher Deckers, chrriis@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.debug;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.jooq.debug.console.misc.Utils;
|
||||
|
||||
public class StatementExecutionResultSetResult implements StatementExecutionResult {
|
||||
|
||||
public static class TypeInfo {
|
||||
|
||||
private String columnName;
|
||||
private int precision;
|
||||
private int scale;
|
||||
private int nullable = ResultSetMetaData.columnNullableUnknown;
|
||||
|
||||
TypeInfo(ResultSetMetaData metaData, int column) {
|
||||
try {
|
||||
columnName = metaData.getColumnTypeName(column + 1);
|
||||
precision = metaData.getPrecision(column + 1);
|
||||
scale = metaData.getScale(column + 1);
|
||||
nullable = metaData.isNullable(column + 1);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(columnName);
|
||||
if(precision != 0) {
|
||||
sb.append(" (" + precision + (scale != 0? ", " + scale: "") + ")");
|
||||
}
|
||||
if(nullable != ResultSetMetaData.columnNullableUnknown) {
|
||||
sb.append(nullable == ResultSetMetaData.columnNoNulls? " not null": " null");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ResultSet rs;
|
||||
private String[] columnNames;
|
||||
private TypeInfo[] typeInfos;
|
||||
private Class<?>[] columnClasses;
|
||||
private Object[][] rowData;
|
||||
private int rowCount;
|
||||
private long resultSetParsingDuration;
|
||||
private int retainParsedRSDataRowCountThreshold;
|
||||
private boolean isReadOnly;
|
||||
|
||||
public StatementExecutionResultSetResult(ResultSet rs, String[] columnNames, TypeInfo[] typeInfos, Class<?>[] columnClasses, Object[][] rowData, int rowCount, long resultSetParsingDuration, int retainParsedRSDataRowCountThreshold, boolean isReadOnly) {
|
||||
this.rs = rs;
|
||||
this.columnNames = columnNames;
|
||||
this.typeInfos = typeInfos;
|
||||
this.columnClasses = columnClasses;
|
||||
this.rowData = rowData;
|
||||
this.rowCount = rowCount;
|
||||
this.resultSetParsingDuration = resultSetParsingDuration;
|
||||
this.retainParsedRSDataRowCountThreshold = retainParsedRSDataRowCountThreshold;
|
||||
this.isReadOnly = isReadOnly;
|
||||
}
|
||||
|
||||
public String[] getColumnNames() {
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
public TypeInfo[] getTypeInfos() {
|
||||
return typeInfos;
|
||||
}
|
||||
|
||||
public Class<?>[] getColumnClasses() {
|
||||
return columnClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the data or an empty array of arrays if <code>rowCount</code> is over <code>retainParsedRSDataRowCountThreshold</code>.
|
||||
*/
|
||||
public Object[][] getRowData() {
|
||||
return rowData;
|
||||
}
|
||||
|
||||
public int getRowCount() {
|
||||
return rowCount;
|
||||
}
|
||||
|
||||
public long getResultSetParsingDuration() {
|
||||
return resultSetParsingDuration;
|
||||
}
|
||||
|
||||
public int getRetainParsedRSDataRowCountThreshold() {
|
||||
return retainParsedRSDataRowCountThreshold;
|
||||
}
|
||||
|
||||
public boolean deleteRow(int row) {
|
||||
try {
|
||||
rs.absolute(row);
|
||||
rs.deleteRow();
|
||||
Object[][] newRowData = new Object[rowData.length - 1][];
|
||||
System.arraycopy(rowData, 0, newRowData, 0, row);
|
||||
System.arraycopy(rowData, row + 1, newRowData, row, newRowData.length - row - 1);
|
||||
rowData = newRowData;
|
||||
return true;
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean setValueAt(Object o, int row, int col) {
|
||||
if(Utils.equals(o, rowData[row][col])) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
rs.absolute(row + 1);
|
||||
rs.updateObject(col + 1, o);
|
||||
rs.updateRow();
|
||||
rowData[row][col] = o;
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
rs.cancelRowUpdates();
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEditable() {
|
||||
try {
|
||||
return rs.getConcurrency() == ResultSet.CONCUR_UPDATABLE && !isReadOnly;
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* Christopher Deckers, chrriis@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.debug;
|
||||
|
||||
|
||||
public interface StatementExecutor {
|
||||
|
||||
public StatementExecution execute();
|
||||
|
||||
public void stopExecution();
|
||||
|
||||
}
|
||||
@ -0,0 +1,301 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* Christopher Deckers, chrriis@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.debug;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.debug.StatementExecutionResultSetResult.TypeInfo;
|
||||
import org.jooq.debug.console.DatabaseDescriptor;
|
||||
import org.jooq.debug.console.misc.Utils;
|
||||
|
||||
public class StatementExecutorImpl implements StatementExecutor {
|
||||
|
||||
private DatabaseDescriptor databaseDescriptor;
|
||||
private String sql;
|
||||
private int maxRSRowsParsing;
|
||||
private int retainParsedRSDataRowCountThreshold;
|
||||
|
||||
public StatementExecutorImpl(DatabaseDescriptor databaseDescriptor, String sql, int maxRSRowsParsing, int retainParsedRSDataRowCountThreshold) {
|
||||
this.databaseDescriptor = databaseDescriptor;
|
||||
this.sql = sql;
|
||||
this.maxRSRowsParsing = maxRSRowsParsing;
|
||||
this.retainParsedRSDataRowCountThreshold = retainParsedRSDataRowCountThreshold;
|
||||
}
|
||||
|
||||
private volatile Connection conn;
|
||||
private volatile Statement stmt;
|
||||
|
||||
private volatile Thread evaluationThread;
|
||||
|
||||
@Override
|
||||
public StatementExecution execute() {
|
||||
boolean isAllowed = true;
|
||||
if(databaseDescriptor.isReadOnly()) {
|
||||
String simplifiedSql = sql.replaceAll("'[^']*'", "");
|
||||
Matcher matcher = Pattern.compile("[a-zA-Z_0-9\\$]+").matcher(simplifiedSql);
|
||||
boolean isFirst = true;
|
||||
while(matcher.find()) {
|
||||
String word = simplifiedSql.substring(matcher.start(), matcher.end()).toUpperCase(Locale.ENGLISH);
|
||||
if(isFirst && !word.equals("SELECT")) {
|
||||
isAllowed = false;
|
||||
break;
|
||||
}
|
||||
isFirst = false;
|
||||
for(String keyword: new String[] {
|
||||
"INSERT",
|
||||
"UPDATE",
|
||||
"DELETE",
|
||||
"ALTER",
|
||||
"DROP",
|
||||
"CREATE",
|
||||
"EXEC",
|
||||
"EXECUTE",
|
||||
}) {
|
||||
if(word.equals(keyword)) {
|
||||
isAllowed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!isAllowed) {
|
||||
return new StatementExecution(0, new StatementExecutionMessageResult("The database is not editable but the statement to evaluate is a modification statement!", true));
|
||||
}
|
||||
closeConnection();
|
||||
evaluationThread = Thread.currentThread();
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
conn = databaseDescriptor.createConnection();
|
||||
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
|
||||
// If no error, adjust start to begining of actual execution.
|
||||
start = System.currentTimeMillis();
|
||||
if(evaluationThread != Thread.currentThread()) {
|
||||
long executionDuration = System.currentTimeMillis() - start;
|
||||
return new StatementExecution(executionDuration, new StatementExecutionMessageResult("Interrupted by user after " + Utils.formatDuration(executionDuration), true));
|
||||
}
|
||||
boolean executeResult;
|
||||
try {
|
||||
executeResult = stmt.execute(sql);
|
||||
} catch(SQLException e) {
|
||||
long executionDuration = System.currentTimeMillis() - start;
|
||||
if(evaluationThread != Thread.currentThread()) {
|
||||
return new StatementExecution(executionDuration, new StatementExecutionMessageResult("Interrupted by user after " + Utils.formatDuration(executionDuration), true));
|
||||
}
|
||||
return new StatementExecution(executionDuration, new StatementExecutionMessageResult(e));
|
||||
}
|
||||
final long executionDuration = System.currentTimeMillis() - start;
|
||||
if(evaluationThread != Thread.currentThread()) {
|
||||
return new StatementExecution(executionDuration, new StatementExecutionMessageResult("Interrupted by user after " + Utils.formatDuration(executionDuration), true));
|
||||
}
|
||||
List<StatementExecutionResult> statementExecutionResultList = new ArrayList<StatementExecutionResult>();
|
||||
do {
|
||||
StatementExecutionResult statementExecutionResult;
|
||||
if(executeResult) {
|
||||
final ResultSet rs = stmt.getResultSet();
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
final String[] columnNames = new String[metaData.getColumnCount()];
|
||||
final int[] columnTypes = new int[columnNames.length];
|
||||
final TypeInfo[] typeInfos = new TypeInfo[columnNames.length];
|
||||
final Class<?>[] columnClasses = new Class[columnNames.length];
|
||||
for(int i=0; i<columnNames.length; i++) {
|
||||
columnNames[i] = metaData.getColumnName(i + 1);
|
||||
if(columnNames[i] == null || columnNames[i].length() == 0) {
|
||||
columnNames[i] = " ";
|
||||
}
|
||||
typeInfos[i] = new TypeInfo(metaData, i);
|
||||
int type = metaData.getColumnType(i + 1);
|
||||
columnTypes[i] = type;
|
||||
switch(type) {
|
||||
case Types.CLOB:
|
||||
columnClasses[i] = String.class;
|
||||
break;
|
||||
case Types.BLOB:
|
||||
columnClasses[i] = byte[].class;
|
||||
break;
|
||||
default:
|
||||
String columnClassName = metaData.getColumnClassName(i + 1);
|
||||
if(columnClassName == null) {
|
||||
System.err.println("Unknown SQL Type for \"" + columnNames[i] + "\" in " + getClass().getSimpleName() + ": " + metaData.getColumnTypeName(i));
|
||||
columnClasses[i] = Object.class;
|
||||
} else {
|
||||
columnClasses[i] = Class.forName(columnClassName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(evaluationThread != Thread.currentThread()) {
|
||||
return new StatementExecution(executionDuration, new StatementExecutionMessageResult("Interrupted by user after " + Utils.formatDuration(executionDuration), true));
|
||||
}
|
||||
final List<Object[]> rowDataList = new ArrayList<Object[]>();
|
||||
int rowCount = 0;
|
||||
long rsStart = System.currentTimeMillis();
|
||||
while(rs.next() && rowCount < maxRSRowsParsing) {
|
||||
if(evaluationThread != Thread.currentThread()) {
|
||||
return new StatementExecution(executionDuration, new StatementExecutionMessageResult("Interrupted by user after " + Utils.formatDuration(executionDuration), true));
|
||||
}
|
||||
rowCount++;
|
||||
Object[] rowData = new Object[columnNames.length];
|
||||
for(int i=0; i<columnNames.length; i++) {
|
||||
switch(columnTypes[i]) {
|
||||
case Types.CLOB: {
|
||||
Clob clob = rs.getClob(i + 1);
|
||||
if(clob != null) {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
char[] chars = new char[1024];
|
||||
Reader reader = new BufferedReader(clob.getCharacterStream());
|
||||
for(int count; (count=reader.read(chars))>=0; ) {
|
||||
stringWriter.write(chars, 0, count);
|
||||
}
|
||||
rowData[i] = stringWriter.toString();
|
||||
} else {
|
||||
rowData[i] = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Types.BLOB: {
|
||||
Blob blob = rs.getBlob(i + 1);
|
||||
if(blob != null) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] bytes = new byte[1024];
|
||||
InputStream in = new BufferedInputStream(blob.getBinaryStream());
|
||||
for(int count; (count=in.read(bytes))>=0; ) {
|
||||
baos.write(bytes, 0, count);
|
||||
}
|
||||
rowData[i] = baos.toByteArray();
|
||||
} else {
|
||||
rowData[i] = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Object object = rs.getObject(i + 1);
|
||||
if(object != null) {
|
||||
String className = object.getClass().getName();
|
||||
if ("oracle.sql.TIMESTAMP".equals(className) || "oracle.sql.TIMESTAMPTZ".equals(className)) {
|
||||
object = rs.getTimestamp(i + 1);
|
||||
}
|
||||
// Probably something to do for oracle.sql.DATE
|
||||
}
|
||||
rowData[i] = object;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(rowCount <= retainParsedRSDataRowCountThreshold) {
|
||||
rowDataList.add(rowData);
|
||||
} else if(rowCount == retainParsedRSDataRowCountThreshold + 1) {
|
||||
rowDataList.clear();
|
||||
}
|
||||
}
|
||||
final long resultSetParsingDuration = System.currentTimeMillis() - rsStart;
|
||||
statementExecutionResult = new StatementExecutionResultSetResult(rs, columnNames, typeInfos, columnClasses, rowDataList.toArray(new Object[0][]), rowCount, resultSetParsingDuration, retainParsedRSDataRowCountThreshold, databaseDescriptor.isReadOnly());
|
||||
} else {
|
||||
final int updateCount = stmt.getUpdateCount();
|
||||
statementExecutionResult = new StatementExecutionMessageResult(Utils.formatDuration(executionDuration) + "> " + updateCount + " row(s) affected.", false);
|
||||
}
|
||||
if(databaseDescriptor.getSQLDialect() == SQLDialect.SQLSERVER) {
|
||||
try {
|
||||
executeResult = stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT);
|
||||
} catch(Exception e) {
|
||||
executeResult = stmt.getMoreResults();
|
||||
}
|
||||
} else {
|
||||
executeResult = false;
|
||||
}
|
||||
statementExecutionResultList.add(statementExecutionResult);
|
||||
} while(executeResult || stmt.getUpdateCount() != -1);
|
||||
return new StatementExecution(executionDuration, statementExecutionResultList.toArray(new StatementExecutionResult[0]));
|
||||
} catch(Exception e) {
|
||||
long executionDuration = System.currentTimeMillis() - start;
|
||||
return new StatementExecution(executionDuration, new StatementExecutionMessageResult(e));
|
||||
} finally {
|
||||
if(databaseDescriptor.isReadOnly()) {
|
||||
closeConnection();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
private void closeConnection() {
|
||||
if (conn != null) {
|
||||
if (stmt != null) {
|
||||
try {
|
||||
stmt.cancel();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
stmt.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
stmt = null;
|
||||
try {
|
||||
conn.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
conn = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopExecution() {
|
||||
if(evaluationThread != null) {
|
||||
evaluationThread = null;
|
||||
closeConnection();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -59,7 +59,6 @@ import java.awt.font.TextAttribute;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -89,8 +88,9 @@ import javax.swing.event.ChangeListener;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.debug.Debugger;
|
||||
import org.jooq.debug.DebuggerRegistry;
|
||||
import org.jooq.debug.LocalDebugger;
|
||||
import org.jooq.debug.console.remote.RemoteDebuggerClient;
|
||||
|
||||
/**
|
||||
@ -99,11 +99,13 @@ import org.jooq.debug.console.remote.RemoteDebuggerClient;
|
||||
@SuppressWarnings("serial")
|
||||
public class Console extends JFrame {
|
||||
|
||||
private Debugger debugger;
|
||||
private JTabbedPane mainTabbedPane;
|
||||
private JTabbedPane editorTabbedPane;
|
||||
|
||||
public Console(final DatabaseDescriptor editorDatabaseDescriptor, boolean isShowingLoggingTab) {
|
||||
public Console(final Debugger debugger, boolean isShowingLoggingTab) {
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
this.debugger = debugger;
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
JMenu fileMenu = new JMenu("File");
|
||||
fileMenu.setMnemonic('F');
|
||||
@ -193,15 +195,15 @@ public class Console extends JFrame {
|
||||
setJMenuBar(menuBar);
|
||||
mainTabbedPane = new JTabbedPane();
|
||||
String title = "jOOQ Console";
|
||||
if(editorDatabaseDescriptor != null) {
|
||||
String schemaName = editorDatabaseDescriptor.getSchema().getName();
|
||||
if(schemaName != null && schemaName.length() != 0) {
|
||||
title += " - " + schemaName;
|
||||
}
|
||||
}
|
||||
// if(editorDatabaseDescriptor != null) {
|
||||
// String schemaName = editorDatabaseDescriptor.getSchema().getName();
|
||||
// if(schemaName != null && schemaName.length() != 0) {
|
||||
// title += " - " + schemaName;
|
||||
// }
|
||||
// }
|
||||
setTitle(title);
|
||||
if(editorDatabaseDescriptor != null) {
|
||||
addEditorTab(editorDatabaseDescriptor);
|
||||
if(debugger.isExecutionSupported()) {
|
||||
addEditorTab();
|
||||
}
|
||||
if(isShowingLoggingTab) {
|
||||
addLoggerTab();
|
||||
@ -210,7 +212,7 @@ public class Console extends JFrame {
|
||||
setLocationByPlatform(true);
|
||||
setSize(800, 600);
|
||||
addNotify();
|
||||
if(editorDatabaseDescriptor != null) {
|
||||
if(debugger.isExecutionSupported()) {
|
||||
getFocusedEditorPane().adjustDefaultFocus();
|
||||
}
|
||||
addWindowListener(new WindowAdapter() {
|
||||
@ -231,7 +233,7 @@ public class Console extends JFrame {
|
||||
}
|
||||
if(editorTabbedPane != null) {
|
||||
for(int i=editorTabbedPane.getTabCount()-2; i>=0; i--) {
|
||||
((EditorPane)editorTabbedPane.getComponentAt(i)).closeConnection();
|
||||
((EditorPane)editorTabbedPane.getComponentAt(i)).closeLastExecution();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -239,13 +241,13 @@ public class Console extends JFrame {
|
||||
private LoggerPane sqlLoggerPane;
|
||||
|
||||
private void addLoggerTab() {
|
||||
sqlLoggerPane = new LoggerPane();
|
||||
sqlLoggerPane = new LoggerPane(debugger);
|
||||
mainTabbedPane.addTab("Logger", sqlLoggerPane);
|
||||
}
|
||||
|
||||
private void addEditorTab(final DatabaseDescriptor databaseDescriptor) {
|
||||
private void addEditorTab() {
|
||||
JPanel editorsPane = new JPanel(new BorderLayout());
|
||||
final String[] tableNames = getTableNames(databaseDescriptor);
|
||||
final String[] tableNames = debugger.getTableNames();
|
||||
final JList tableNamesJList = new JList(tableNames);
|
||||
tableNamesJList.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
@ -265,7 +267,7 @@ public class Console extends JFrame {
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
if(!isAdjusting && editorTabbedPane.getSelectedIndex() == editorTabbedPane.getTabCount() - 1) {
|
||||
addSQLEditorPane(databaseDescriptor);
|
||||
addSQLEditorPane();
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -374,14 +376,21 @@ public class Console extends JFrame {
|
||||
tableNamePane.add(tableNameFilterTextField, BorderLayout.NORTH);
|
||||
tableNamePane.add(new JScrollPane(tableNamesJList), BorderLayout.CENTER);
|
||||
JSplitPane horizontalSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, tableNamePane, editorTabbedPane);
|
||||
addSQLEditorPane(databaseDescriptor);
|
||||
addSQLEditorPane();
|
||||
editorsPane.add(horizontalSplitPane, BorderLayout.CENTER);
|
||||
mainTabbedPane.addTab("Editor", editorsPane);
|
||||
}
|
||||
|
||||
public static void openConsole(DatabaseDescriptor databaseDescriptor, boolean isLoggingActive) {
|
||||
Console sqlConsoleFrame = new Console(databaseDescriptor, true);
|
||||
final LocalDebugger debugger = new LocalDebugger(databaseDescriptor);
|
||||
Console sqlConsoleFrame = new Console(debugger, true);
|
||||
sqlConsoleFrame.setLoggingActive(isLoggingActive);
|
||||
sqlConsoleFrame.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
DebuggerRegistry.removeSqlQueryDebugger(debugger);
|
||||
}
|
||||
});
|
||||
sqlConsoleFrame.setVisible(true);
|
||||
}
|
||||
|
||||
@ -396,10 +405,10 @@ public class Console extends JFrame {
|
||||
private boolean isAdjusting;
|
||||
private int contextCount = 1;
|
||||
|
||||
private void addSQLEditorPane(DatabaseDescriptor databaseDescriptor) {
|
||||
private void addSQLEditorPane() {
|
||||
isAdjusting = true;
|
||||
int index = editorTabbedPane.getTabCount() - 1;
|
||||
final EditorPane sqlEditorPane = new EditorPane(databaseDescriptor);
|
||||
final EditorPane sqlEditorPane = new EditorPane(debugger);
|
||||
String title = "Context " + contextCount++;
|
||||
editorTabbedPane.insertTab(title, null, sqlEditorPane, null, index);
|
||||
final JPanel tabComponent = new JPanel(new BorderLayout());
|
||||
@ -417,7 +426,7 @@ public class Console extends JFrame {
|
||||
if(editorTabbedPane.getTabCount() > 2) {
|
||||
for(int i=editorTabbedPane.getTabCount()-1; i>=0; i--) {
|
||||
if(editorTabbedPane.getTabComponentAt(i) == tabComponent) {
|
||||
((EditorPane)editorTabbedPane.getComponentAt(i)).closeConnection();
|
||||
((EditorPane)editorTabbedPane.getComponentAt(i)).closeLastExecution();
|
||||
editorTabbedPane.removeTabAt(i);
|
||||
if(i == editorTabbedPane.getTabCount() - 1) {
|
||||
editorTabbedPane.setSelectedIndex(i - 1);
|
||||
@ -458,25 +467,15 @@ public class Console extends JFrame {
|
||||
return (EditorPane)editorTabbedPane.getSelectedComponent();
|
||||
}
|
||||
|
||||
private static String[] getTableNames(DatabaseDescriptor databaseDescriptor) {
|
||||
List<Table<?>> tableList = databaseDescriptor.getSchema().getTables();
|
||||
List<String> tableNameList = new ArrayList<String>();
|
||||
for(Table<? extends Record> table: tableList) {
|
||||
String tableName = table.getName();
|
||||
tableNameList.add(tableName);
|
||||
}
|
||||
Collections.sort(tableNameList, String.CASE_INSENSITIVE_ORDER);
|
||||
return tableNameList.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if(args.length < 2) {
|
||||
System.out.println("Please specify IP and port of a running RemoteDebuggerServer");
|
||||
System.out.println("Usage: Console <ip> <port>");
|
||||
return;
|
||||
}
|
||||
final Debugger debugger;
|
||||
try {
|
||||
new RemoteDebuggerClient(args[0], Integer.parseInt(args[1]));
|
||||
debugger = new RemoteDebuggerClient(args[0], Integer.parseInt(args[1]));
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
@ -489,7 +488,7 @@ public class Console extends JFrame {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Console sqlConsoleFrame = new Console(null, true);
|
||||
Console sqlConsoleFrame = new Console(debugger, true);
|
||||
sqlConsoleFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
sqlConsoleFrame.setVisible(true);
|
||||
}
|
||||
|
||||
@ -53,32 +53,15 @@ import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -121,10 +104,12 @@ import javax.swing.table.TableCellRenderer;
|
||||
import javax.swing.table.TableRowSorter;
|
||||
import javax.swing.text.BadLocationException;
|
||||
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.debug.Debugger;
|
||||
import org.jooq.debug.StatementExecution;
|
||||
import org.jooq.debug.StatementExecutionMessageResult;
|
||||
import org.jooq.debug.StatementExecutionResult;
|
||||
import org.jooq.debug.StatementExecutionResultSetResult;
|
||||
import org.jooq.debug.StatementExecutor;
|
||||
import org.jooq.debug.console.misc.JTableX;
|
||||
import org.jooq.debug.console.misc.Utils;
|
||||
|
||||
@ -140,17 +125,18 @@ public class EditorPane extends JPanel {
|
||||
private boolean isUsingMaxRowCount = true;
|
||||
private JFormattedTextField displayedRowCountField;
|
||||
|
||||
private DatabaseDescriptor databaseDescriptor;
|
||||
private SqlTextArea editorTextArea;
|
||||
private JPanel southPanel = new JPanel(new BorderLayout());
|
||||
private boolean isDBEditable;
|
||||
private Debugger debugger;
|
||||
private StatementExecutor lastStatementExecutor;
|
||||
private JButton startButton;
|
||||
private JButton stopButton;
|
||||
|
||||
EditorPane(DatabaseDescriptor databaseDescriptor) {
|
||||
EditorPane(Debugger debugger) {
|
||||
super(new BorderLayout());
|
||||
this.databaseDescriptor = databaseDescriptor;
|
||||
this.isDBEditable = !databaseDescriptor.isReadOnly();
|
||||
this.debugger = debugger;
|
||||
this.isDBEditable = !debugger.isReadOnly();
|
||||
setOpaque(false);
|
||||
JPanel northPanel = new JPanel(new BorderLayout());
|
||||
northPanel.setOpaque(false);
|
||||
@ -177,8 +163,7 @@ public class EditorPane extends JPanel {
|
||||
stopButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
evaluationThread = null;
|
||||
closeConnection();
|
||||
closeLastExecution();
|
||||
}
|
||||
});
|
||||
northWestPanel.add(stopButton);
|
||||
@ -225,10 +210,7 @@ public class EditorPane extends JPanel {
|
||||
new Thread("SQLConsole - Interruption") {
|
||||
@Override
|
||||
public void run() {
|
||||
if(evaluationThread != null) {
|
||||
evaluationThread = null;
|
||||
closeConnection();
|
||||
}
|
||||
closeLastExecution();
|
||||
}
|
||||
}.start();
|
||||
break;
|
||||
@ -312,58 +294,19 @@ public class EditorPane extends JPanel {
|
||||
southPanel.repaint();
|
||||
}
|
||||
|
||||
private static class TypeInfo {
|
||||
|
||||
private String columnName;
|
||||
private int precision;
|
||||
private int scale;
|
||||
private int nullable = ResultSetMetaData.columnNullableUnknown;
|
||||
|
||||
TypeInfo(ResultSetMetaData metaData, int column) {
|
||||
try {
|
||||
columnName = metaData.getColumnTypeName(column);
|
||||
precision = metaData.getPrecision(column);
|
||||
scale = metaData.getScale(column);
|
||||
nullable = metaData.isNullable(column);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(columnName);
|
||||
if(precision != 0) {
|
||||
sb.append(" (" + precision + (scale != 0? ", " + scale: "") + ")");
|
||||
}
|
||||
if(nullable != ResultSetMetaData.columnNullableUnknown) {
|
||||
sb.append(nullable == ResultSetMetaData.columnNoNulls? " not null": " null");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private volatile Connection conn;
|
||||
private volatile Statement stmt;
|
||||
|
||||
private volatile Thread evaluationThread;
|
||||
|
||||
private void evaluate_unrestricted(final String sql) {
|
||||
final int maxDisplayedRowCount = ((Number)displayedRowCountField.getValue()).intValue();
|
||||
evaluationThread = new Thread("SQLConsole - Evaluation") {
|
||||
Thread evaluationThread = new Thread("SQLConsole - Evaluation") {
|
||||
@Override
|
||||
public void run() {
|
||||
evaluate_unrestricted_nothread(sql, maxDisplayedRowCount);
|
||||
evaluationThread = null;
|
||||
}
|
||||
};
|
||||
evaluationThread.start();
|
||||
}
|
||||
|
||||
private void evaluate_unrestricted_nothread(final String sql, final int maxDisplayedRowCount) {
|
||||
closeConnection();
|
||||
closeLastExecution();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -372,194 +315,14 @@ public class EditorPane extends JPanel {
|
||||
stopButton.setToolTipText("Query started on " + Utils.formatDateTimeTZ(new Date()));
|
||||
}
|
||||
});
|
||||
StatementExecutor statementExecutor;
|
||||
synchronized (debugger) {
|
||||
statementExecutor = debugger.createStatementExecutor(sql, isUsingMaxRowCount? MAX_ROW_COUNT: Integer.MAX_VALUE, maxDisplayedRowCount);
|
||||
lastStatementExecutor = statementExecutor;
|
||||
}
|
||||
StatementExecution statementExecution;
|
||||
try {
|
||||
conn = databaseDescriptor.createConnection();
|
||||
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
|
||||
final long start = System.currentTimeMillis();
|
||||
if(evaluationThread != Thread.currentThread()) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setMessage(addResultPane(), "Interrupted by user after " + Utils.formatDuration(System.currentTimeMillis() - start), true);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
boolean executeResult;
|
||||
try {
|
||||
executeResult = stmt.execute(sql);
|
||||
} catch(SQLException e) {
|
||||
if(evaluationThread != Thread.currentThread()) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setMessage(addResultPane(), "Interrupted by user after " + Utils.formatDuration(System.currentTimeMillis() - start), true);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
final long duration = System.currentTimeMillis() - start;
|
||||
if(evaluationThread != Thread.currentThread()) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setMessage(addResultPane(), "Interrupted by user after " + Utils.formatDuration(duration), true);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
do {
|
||||
if(executeResult) {
|
||||
final ResultSet rs = stmt.getResultSet();
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
// The first column is the line count
|
||||
final String[] columnNames = new String[metaData.getColumnCount() + 1];
|
||||
final int[] columnTypes = new int[columnNames.length];
|
||||
final TypeInfo[] typeInfos = new TypeInfo[columnNames.length];
|
||||
final Class<?>[] columnClasses = new Class[columnNames.length];
|
||||
columnNames[0] = "";
|
||||
columnClasses[0] = Integer.class;
|
||||
for(int i=1; i<columnNames.length; i++) {
|
||||
columnNames[i] = metaData.getColumnName(i);
|
||||
if(columnNames[i] == null || columnNames[i].length() == 0) {
|
||||
columnNames[i] = " ";
|
||||
}
|
||||
typeInfos[i] = new TypeInfo(metaData, i);
|
||||
int type = metaData.getColumnType(i);
|
||||
columnTypes[i] = type;
|
||||
switch(type) {
|
||||
case Types.CLOB:
|
||||
columnClasses[i] = String.class;
|
||||
break;
|
||||
case Types.BLOB:
|
||||
columnClasses[i] = byte[].class;
|
||||
break;
|
||||
default:
|
||||
String columnClassName = metaData.getColumnClassName(i);
|
||||
if(columnClassName == null) {
|
||||
System.err.println("Unknown SQL Type for \"" + columnNames[i] + "\" in SQLEditorPane: " + metaData.getColumnTypeName(i));
|
||||
columnClasses[i] = Object.class;
|
||||
} else {
|
||||
columnClasses[i] = Class.forName(columnClassName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(evaluationThread != Thread.currentThread()) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setMessage(addResultPane(), "Interrupted by user after " + Utils.formatDuration(duration), true);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
final List<Object[]> rowDataList = new ArrayList<Object[]>();
|
||||
int rowCount = 0;
|
||||
long rsStart = System.currentTimeMillis();
|
||||
while(rs.next() && (!isUsingMaxRowCount || rowCount < MAX_ROW_COUNT)) {
|
||||
if(evaluationThread != Thread.currentThread()) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setMessage(addResultPane(), "Interrupted by user after " + Utils.formatDuration(duration), true);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
rowCount++;
|
||||
Object[] rowData = new Object[columnNames.length];
|
||||
rowData[0] = rowCount;
|
||||
for(int i=1; i<columnNames.length; i++) {
|
||||
switch(columnTypes[i]) {
|
||||
case Types.CLOB: {
|
||||
Clob clob = rs.getClob(i);
|
||||
if(clob != null) {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
char[] chars = new char[1024];
|
||||
Reader reader = new BufferedReader(clob.getCharacterStream());
|
||||
for(int count; (count=reader.read(chars))>=0; ) {
|
||||
stringWriter.write(chars, 0, count);
|
||||
}
|
||||
rowData[i] = stringWriter.toString();
|
||||
} else {
|
||||
rowData[i] = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Types.BLOB: {
|
||||
Blob blob = rs.getBlob(i);
|
||||
if(blob != null) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] bytes = new byte[1024];
|
||||
InputStream in = new BufferedInputStream(blob.getBinaryStream());
|
||||
for(int count; (count=in.read(bytes))>=0; ) {
|
||||
baos.write(bytes, 0, count);
|
||||
}
|
||||
rowData[i] = baos.toByteArray();
|
||||
} else {
|
||||
rowData[i] = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Object object = rs.getObject(i);
|
||||
if(object != null) {
|
||||
String className = object.getClass().getName();
|
||||
if ("oracle.sql.TIMESTAMP".equals(className) || "oracle.sql.TIMESTAMPTZ".equals(className)) {
|
||||
object = rs.getTimestamp(i);
|
||||
}
|
||||
// Probably something to do for oracle.sql.DATE
|
||||
}
|
||||
rowData[i] = object;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(rowCount <= maxDisplayedRowCount) {
|
||||
rowDataList.add(rowData);
|
||||
} else if(rowCount == maxDisplayedRowCount + 1) {
|
||||
rowDataList.clear();
|
||||
}
|
||||
}
|
||||
final long rsDuration = System.currentTimeMillis() - rsStart;
|
||||
final int rowCount_ = rowCount;
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
addResultTable(sql, duration, rs, columnNames, typeInfos, columnClasses, rowDataList, rowCount_, rsDuration, maxDisplayedRowCount);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
final int updateCount = stmt.getUpdateCount();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setMessage(addResultPane(), Utils.formatDuration(duration) + "> " + updateCount + " row(s) affected.", false);
|
||||
}
|
||||
});
|
||||
}
|
||||
if(databaseDescriptor.getSQLDialect() == SQLDialect.SQLSERVER) {
|
||||
try {
|
||||
executeResult = stmt.getMoreResults(Statement.KEEP_CURRENT_RESULT);
|
||||
} catch(Exception e) {
|
||||
executeResult = stmt.getMoreResults();
|
||||
}
|
||||
} else {
|
||||
executeResult = false;
|
||||
}
|
||||
} while(executeResult || stmt.getUpdateCount() != -1);
|
||||
} catch(Exception e) {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(stringWriter));
|
||||
final String message = stringWriter.toString();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setMessage(addResultPane(), message, true);
|
||||
}
|
||||
});
|
||||
statementExecution = statementExecutor.execute();
|
||||
} finally {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
@ -569,86 +332,40 @@ public class EditorPane extends JPanel {
|
||||
stopButton.setToolTipText(null);
|
||||
}
|
||||
});
|
||||
if(!isDBEditable) {
|
||||
closeConnection();
|
||||
}
|
||||
}
|
||||
final StatementExecutionResult[] results = statementExecution.getResults();
|
||||
final long executionDuration = statementExecution.getExecutionDuration();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for(StatementExecutionResult result: results) {
|
||||
if(result instanceof StatementExecutionMessageResult) {
|
||||
StatementExecutionMessageResult messageResult = (StatementExecutionMessageResult)result;
|
||||
setMessage(addResultPane(), messageResult.getMessage(), messageResult.isError());
|
||||
} else if(result instanceof StatementExecutionResultSetResult) {
|
||||
addResultTable(sql, executionDuration, (StatementExecutionResultSetResult)result);
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown result class: " + result.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addResultTable(final String sql, long duration, final ResultSet rs, final String[] columnNames, final TypeInfo[] typeInfos, final Class<?>[] columnClasses, final List<Object[]> rowDataList, int rowCount, long rsDuration, int maxDisplayedRowCount) {
|
||||
private void addResultTable(final String sql, long duration, final StatementExecutionResultSetResult resultSetResult) {
|
||||
int rowCount = resultSetResult.getRowCount();
|
||||
JPanel resultPane = addResultPane();
|
||||
final JLabel label = new JLabel(" " + rowCount + " rows");
|
||||
FlowLayout flowLayout = new FlowLayout(FlowLayout.LEFT, 0, 0);
|
||||
flowLayout.setAlignOnBaseline(true);
|
||||
JPanel statusCountPane = new JPanel(flowLayout);
|
||||
if(rowCount <= maxDisplayedRowCount) {
|
||||
final JTableX table = new JTableX(new AbstractTableModel() {
|
||||
@Override
|
||||
public String getColumnName(int column) {
|
||||
return columnNames[column].toString();
|
||||
}
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return rowDataList.size();
|
||||
}
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return columnNames.length;
|
||||
}
|
||||
@Override
|
||||
public Object getValueAt(int row, int col) {
|
||||
return rowDataList.get(row)[col];
|
||||
}
|
||||
@Override
|
||||
public void setValueAt(Object o, int row, int col) {
|
||||
if(Utils.equals(o, rowDataList.get(row)[col])) {
|
||||
return;
|
||||
}
|
||||
int dbRow = (Integer)rowDataList.get(row)[0];
|
||||
try {
|
||||
rs.absolute(dbRow);
|
||||
rs.updateObject(col, o);
|
||||
rs.updateRow();
|
||||
rowDataList.get(row)[col] = o;
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
rs.cancelRowUpdates();
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
try {
|
||||
if(rs.getConcurrency() == ResultSet.CONCUR_UPDATABLE) {
|
||||
return isDBEditable && columnIndex > 0;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
return columnClasses[columnIndex];
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
public TableCellEditor getCellEditor(int row, int column) {
|
||||
TableCellEditor editor = super.getCellEditor(row, column);
|
||||
if(editor instanceof DefaultCellEditor) {
|
||||
DefaultCellEditor defaultEditor = (DefaultCellEditor) editor;
|
||||
defaultEditor.setClickCountToStart(2);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
};
|
||||
if(rowCount <= resultSetResult.getRetainParsedRSDataRowCountThreshold()) {
|
||||
final JTableX table = new ResultTable(resultSetResult);
|
||||
JTableHeader tableHeader = new JTableHeader(table.getColumnModel()) {
|
||||
@Override
|
||||
public String getToolTipText(MouseEvent e) {
|
||||
int col = getTable().convertColumnIndexToModel(columnAtPoint(e.getPoint()));
|
||||
return col == 0? null: typeInfos[col].toString();
|
||||
return col == 0? null: resultSetResult.getTypeInfos()[col - 1].toString();
|
||||
}
|
||||
};
|
||||
ToolTipManager.sharedInstance().registerComponent(tableHeader);
|
||||
@ -716,7 +433,7 @@ public class EditorPane extends JPanel {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
int selectedRowCount = table.getSelectedRowCount();
|
||||
label.setText(" " + rowDataList.size() + " rows" + (selectedRowCount == 0? "": " - " + selectedRowCount + " selected rows"));
|
||||
label.setText(" " + resultSetResult.getRowData().length + " rows" + (selectedRowCount == 0? "": " - " + selectedRowCount + " selected rows"));
|
||||
}
|
||||
});
|
||||
table.addMouseListener(new MouseAdapter() {
|
||||
@ -737,14 +454,7 @@ public class EditorPane extends JPanel {
|
||||
if(!e.isPopupTrigger()) {
|
||||
return;
|
||||
}
|
||||
boolean isEditable = false;
|
||||
try {
|
||||
if(rs.getConcurrency() == ResultSet.CONCUR_UPDATABLE) {
|
||||
isEditable = isDBEditable;
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
isEditable = false;
|
||||
}
|
||||
boolean isEditable = resultSetResult.isEditable();
|
||||
JPopupMenu menu = new JPopupMenu();
|
||||
int selectedRowCount = table.getSelectedRowCount();
|
||||
int selectedColumnCount = table.getSelectedColumnCount();
|
||||
@ -778,14 +488,9 @@ public class EditorPane extends JPanel {
|
||||
Arrays.sort(selectedRows);
|
||||
for(int i=selectedRows.length-1; i>=0; i--) {
|
||||
int row = selectedRows[i];
|
||||
int dbRow = (Integer)rowDataList.get(row)[0];
|
||||
try {
|
||||
rs.absolute(dbRow);
|
||||
rs.deleteRow();
|
||||
rowDataList.remove(row);
|
||||
boolean isSuccess = resultSetResult.deleteRow(row);
|
||||
if(isSuccess) {
|
||||
((AbstractTableModel)table.getModel()).fireTableRowsDeleted(row, row);
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -868,7 +573,7 @@ public class EditorPane extends JPanel {
|
||||
}
|
||||
statusCountPane.add(label);
|
||||
southPanel.add(statusCountPane, BorderLayout.WEST);
|
||||
southPanel.add(new JLabel(Utils.formatDuration(duration) + " - " + Utils.formatDuration(rsDuration)), BorderLayout.EAST);
|
||||
southPanel.add(new JLabel(Utils.formatDuration(duration) + " - " + Utils.formatDuration(resultSetResult.getResultSetParsingDuration())), BorderLayout.EAST);
|
||||
resultPane.add(southPanel, BorderLayout.SOUTH);
|
||||
southPanel.setToolTipText(sql);
|
||||
resultPane.revalidate();
|
||||
@ -924,24 +629,12 @@ public class EditorPane extends JPanel {
|
||||
return resultPane;
|
||||
}
|
||||
|
||||
void closeConnection() {
|
||||
if (conn != null) {
|
||||
if (stmt != null) {
|
||||
try {
|
||||
stmt.cancel();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
stmt.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
void closeLastExecution() {
|
||||
synchronized (debugger) {
|
||||
if(lastStatementExecutor != null) {
|
||||
lastStatementExecutor.stopExecution();
|
||||
lastStatementExecutor = null;
|
||||
}
|
||||
stmt = null;
|
||||
try {
|
||||
conn.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
conn = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1097,6 +790,66 @@ public class EditorPane extends JPanel {
|
||||
return wordStart;
|
||||
}
|
||||
|
||||
private final class ResultTableModel extends AbstractTableModel {
|
||||
|
||||
private final StatementExecutionResultSetResult resultSetResult;
|
||||
|
||||
private ResultTableModel(StatementExecutionResultSetResult resultSetResult) {
|
||||
this.resultSetResult = resultSetResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int column) {
|
||||
return column == 0? "": resultSetResult.getColumnNames()[column - 1].toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return resultSetResult.getRowData().length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return resultSetResult.getColumnNames().length + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int row, int col) {
|
||||
return col == 0? row + 1: resultSetResult.getRowData()[row][col - 1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(Object o, int row, int col) {
|
||||
resultSetResult.setValueAt(o, row, col - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int col) {
|
||||
return col > 0 && resultSetResult.isEditable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getColumnClass(int col) {
|
||||
return col == 0? Integer.class: resultSetResult.getColumnClasses()[col - 1];
|
||||
}
|
||||
}
|
||||
|
||||
private final class ResultTable extends JTableX {
|
||||
private ResultTable(StatementExecutionResultSetResult resultSetResult) {
|
||||
super(new ResultTableModel(resultSetResult));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableCellEditor getCellEditor(int row, int column) {
|
||||
TableCellEditor editor = super.getCellEditor(row, column);
|
||||
if(editor instanceof DefaultCellEditor) {
|
||||
DefaultCellEditor defaultEditor = (DefaultCellEditor) editor;
|
||||
defaultEditor.setClickCountToStart(2);
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
|
||||
private static enum KeyWordType {
|
||||
DYNAMIC_STATEMENT,
|
||||
TABLE,
|
||||
@ -1124,10 +877,10 @@ public class EditorPane extends JPanel {
|
||||
List<CompletionCandidate> candidateList = new ArrayList<CompletionCandidate>();
|
||||
// Here can add more candidates depending on magic word start.
|
||||
if(candidateList.isEmpty()) {
|
||||
for(String s: getTableNames()) {
|
||||
for(String s: debugger.getTableNames()) {
|
||||
candidateList.add(new CompletionCandidate(KeyWordType.TABLE, s));
|
||||
}
|
||||
for(String s: getTableColumnNames()) {
|
||||
for(String s: debugger.getTableColumnNames()) {
|
||||
candidateList.add(new CompletionCandidate(KeyWordType.TABLE_COlUMN, s));
|
||||
}
|
||||
for(String s: new String[] {
|
||||
@ -1175,29 +928,6 @@ public class EditorPane extends JPanel {
|
||||
return filteredCompletionCandidateList.toArray(new CompletionCandidate[0]);
|
||||
}
|
||||
|
||||
private String[] getTableNames() {
|
||||
List<String> tableNameList = new ArrayList<String>();
|
||||
for(Table<? extends Record> table: databaseDescriptor.getSchema().getTables()) {
|
||||
String tableName = table.getName();
|
||||
tableNameList.add(tableName);
|
||||
}
|
||||
Collections.sort(tableNameList, String.CASE_INSENSITIVE_ORDER);
|
||||
return tableNameList.toArray(new String[0]);
|
||||
}
|
||||
|
||||
private String[] getTableColumnNames() {
|
||||
Set<String> columnNameSet = new HashSet<String>();
|
||||
for(Table<?> table: databaseDescriptor.getSchema().getTables()) {
|
||||
for(Field<?> field: table.getFields()) {
|
||||
String columnName = field.getName();
|
||||
columnNameSet.add(columnName);
|
||||
}
|
||||
}
|
||||
String[] columnNames = columnNameSet.toArray(new String[0]);
|
||||
Arrays.sort(columnNames, String.CASE_INSENSITIVE_ORDER);
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
public void adjustDefaultFocus() {
|
||||
editorTextArea.requestFocusInWindow();
|
||||
}
|
||||
|
||||
@ -97,9 +97,9 @@ import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
|
||||
import org.jooq.debug.Debugger;
|
||||
import org.jooq.debug.DebuggerData;
|
||||
import org.jooq.debug.DebuggerRegistry;
|
||||
import org.jooq.debug.DebuggerResultSetData;
|
||||
import org.jooq.debug.LoggingListener;
|
||||
import org.jooq.debug.QueryLoggingData;
|
||||
import org.jooq.debug.ResultSetLoggingData;
|
||||
import org.jooq.debug.SqlQueryType;
|
||||
import org.jooq.debug.console.misc.JTableX;
|
||||
import org.jooq.debug.console.misc.RichTextTransferable;
|
||||
@ -135,7 +135,7 @@ public class LoggerPane extends JPanel {
|
||||
private final ImageIcon OTHER_ICON = new ImageIcon(getClass().getResource("/org/jooq/debug/console/resources/SqlOther16.png"));
|
||||
private final ImageIcon SELECT_ICON = new ImageIcon(getClass().getResource("/org/jooq/debug/console/resources/SqlSelect16.png"));
|
||||
|
||||
private Debugger sqlQueryDebugger;
|
||||
private Debugger debugger;
|
||||
private JTableX table;
|
||||
private SqlTextArea textArea;
|
||||
private JLabel loggerStatusLabel;
|
||||
@ -147,8 +147,9 @@ public class LoggerPane extends JPanel {
|
||||
private boolean isOtherQueryTypeDisplayed = true;
|
||||
private boolean isScrollLocked;
|
||||
|
||||
public LoggerPane() {
|
||||
public LoggerPane(Debugger debugger) {
|
||||
super(new BorderLayout());
|
||||
this.debugger = debugger;
|
||||
setOpaque(false);
|
||||
JPanel loggerHeaderPanel = new JPanel(new BorderLayout());
|
||||
loggerHeaderPanel.setOpaque(false);
|
||||
@ -359,15 +360,15 @@ public class LoggerPane extends JPanel {
|
||||
return duration < 0? null: duration;
|
||||
}
|
||||
case COLUMN_RS_LIFETIME: {
|
||||
DebuggerResultSetData rsData = queryDebuggingInfo.getSqlQueryDebuggerResultSetData();
|
||||
ResultSetLoggingData rsData = queryDebuggingInfo.getResultSetLoggingData();
|
||||
return rsData == null? null: rsData.getLifeTime();
|
||||
}
|
||||
case COLUMN_RS_READ: {
|
||||
DebuggerResultSetData rsData = queryDebuggingInfo.getSqlQueryDebuggerResultSetData();
|
||||
ResultSetLoggingData rsData = queryDebuggingInfo.getResultSetLoggingData();
|
||||
return rsData == null? null: rsData.getReadCount();
|
||||
}
|
||||
case COLUMN_RS_READ_ROWS: {
|
||||
DebuggerResultSetData rsData = queryDebuggingInfo.getSqlQueryDebuggerResultSetData();
|
||||
ResultSetLoggingData rsData = queryDebuggingInfo.getResultSetLoggingData();
|
||||
return rsData == null? null: rsData.getReadRows();
|
||||
}
|
||||
case COLUMN_DUPLICATION_COUNT: {
|
||||
@ -732,36 +733,36 @@ public class LoggerPane extends JPanel {
|
||||
|
||||
private static class QueryDebuggingInfo {
|
||||
private long timestamp;
|
||||
private DebuggerData sqlQueryDebuggerData;
|
||||
private QueryLoggingData queryLoggingData;
|
||||
private Throwable throwable;
|
||||
private int duplicationCount;
|
||||
public QueryDebuggingInfo(long timestamp, DebuggerData sqlQueryDebuggerData) {
|
||||
public QueryDebuggingInfo(long timestamp, QueryLoggingData queryLoggingData) {
|
||||
this.timestamp = timestamp;
|
||||
this.sqlQueryDebuggerData = sqlQueryDebuggerData;
|
||||
this.queryLoggingData = queryLoggingData;
|
||||
this.throwable = new Exception("Statement Stack trace");
|
||||
throwable.setStackTrace(sqlQueryDebuggerData.getCallerStackTraceElements());
|
||||
throwable.setStackTrace(queryLoggingData.getCallerStackTraceElements());
|
||||
}
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
public DebuggerData getSqlQueryDebuggerData() {
|
||||
return sqlQueryDebuggerData;
|
||||
public QueryLoggingData getQueryLoggingData() {
|
||||
return queryLoggingData;
|
||||
}
|
||||
public Long getPrepardeStatementPreparationDuration() {
|
||||
return sqlQueryDebuggerData.getPreparedStatementPreparationDuration();
|
||||
return queryLoggingData.getPreparedStatementPreparationDuration();
|
||||
}
|
||||
public Long getPrepardeStatementBindingDuration() {
|
||||
return sqlQueryDebuggerData.getPreparedStatementBindingDuration();
|
||||
return queryLoggingData.getPreparedStatementBindingDuration();
|
||||
}
|
||||
public long getExecutionDuration() {
|
||||
return sqlQueryDebuggerData.getExecutionDuration();
|
||||
return queryLoggingData.getExecutionDuration();
|
||||
}
|
||||
public SqlQueryType getQueryType() {
|
||||
return sqlQueryDebuggerData.getQueryType();
|
||||
return queryLoggingData.getQueryType();
|
||||
}
|
||||
public String[] getQueries() {
|
||||
String parameterDescription = sqlQueryDebuggerData.getParameterDescription();
|
||||
String[] queries = sqlQueryDebuggerData.getQueries();
|
||||
String parameterDescription = queryLoggingData.getParameterDescription();
|
||||
String[] queries = queryLoggingData.getQueries();
|
||||
if(parameterDescription != null) {
|
||||
return new String[] {queries[0] + " -> " + parameterDescription};
|
||||
}
|
||||
@ -771,10 +772,10 @@ public class LoggerPane extends JPanel {
|
||||
return throwable;
|
||||
}
|
||||
public String getThreadName() {
|
||||
return sqlQueryDebuggerData.getThreadName();
|
||||
return queryLoggingData.getThreadName();
|
||||
}
|
||||
public long getThreadId() {
|
||||
return sqlQueryDebuggerData.getThreadID();
|
||||
return queryLoggingData.getThreadID();
|
||||
}
|
||||
public void setDuplicationCount(int duplicationCount) {
|
||||
this.duplicationCount = duplicationCount;
|
||||
@ -782,12 +783,12 @@ public class LoggerPane extends JPanel {
|
||||
public int getDuplicationCount() {
|
||||
return duplicationCount;
|
||||
}
|
||||
private DebuggerResultSetData sqlQueryDebuggerResultSetData;
|
||||
public void setSqlQueryDebuggerResultSetData(DebuggerResultSetData sqlQueryDebuggerResultSetData) {
|
||||
this.sqlQueryDebuggerResultSetData = sqlQueryDebuggerResultSetData;
|
||||
private ResultSetLoggingData resultSetLoggingData;
|
||||
public void setResultSetLoggingData(ResultSetLoggingData resultSetLoggingData) {
|
||||
this.resultSetLoggingData = resultSetLoggingData;
|
||||
}
|
||||
public DebuggerResultSetData getSqlQueryDebuggerResultSetData() {
|
||||
return sqlQueryDebuggerResultSetData;
|
||||
public ResultSetLoggingData getResultSetLoggingData() {
|
||||
return resultSetLoggingData;
|
||||
}
|
||||
private int displayedRow = -1;
|
||||
public int getDisplayedRow() {
|
||||
@ -807,15 +808,11 @@ public class LoggerPane extends JPanel {
|
||||
this.isLogging = isLogging;
|
||||
loggerOnButton.setVisible(!isLogging);
|
||||
loggerOffButton.setVisible(isLogging);
|
||||
if(sqlQueryDebugger != null) {
|
||||
DebuggerRegistry.removeSqlQueryDebugger(sqlQueryDebugger);
|
||||
sqlQueryDebugger = null;
|
||||
}
|
||||
if(isLogging) {
|
||||
sqlQueryDebugger = new Debugger() {
|
||||
LoggingListener loggingListener = new LoggingListener() {
|
||||
@Override
|
||||
public void debugQueries(DebuggerData sqlQueryDebuggerData) {
|
||||
debugQueries(new QueryDebuggingInfo(System.currentTimeMillis(), sqlQueryDebuggerData));
|
||||
public void logQueries(QueryLoggingData queryLoggingData) {
|
||||
debugQueries(new QueryDebuggingInfo(System.currentTimeMillis(), queryLoggingData));
|
||||
}
|
||||
public void debugQueries(final QueryDebuggingInfo queryDebuggingInfo) {
|
||||
if(!SwingUtilities.isEventDispatchThread()) {
|
||||
@ -830,20 +827,20 @@ public class LoggerPane extends JPanel {
|
||||
addRow(queryDebuggingInfo);
|
||||
}
|
||||
@Override
|
||||
public void debugResultSet(final int sqlQueryDebuggerDataID, final DebuggerResultSetData sqlQueryDebuggerResultSetData) {
|
||||
public void logResultSet(final int queryLoggingDataID, final ResultSetLoggingData resultSetLoggingData) {
|
||||
if(!SwingUtilities.isEventDispatchThread()) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
debugResultSet(sqlQueryDebuggerDataID, sqlQueryDebuggerResultSetData);
|
||||
logResultSet(queryLoggingDataID, resultSetLoggingData);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
for(int i=queryDebuggingInfoList.size()-1; i>=0; i--) {
|
||||
QueryDebuggingInfo queryDebuggingInfo = queryDebuggingInfoList.get(i);
|
||||
if(queryDebuggingInfo.getSqlQueryDebuggerData().getID() == sqlQueryDebuggerDataID) {
|
||||
queryDebuggingInfo.setSqlQueryDebuggerResultSetData(sqlQueryDebuggerResultSetData);
|
||||
if(queryDebuggingInfo.getQueryLoggingData().getID() == queryLoggingDataID) {
|
||||
queryDebuggingInfo.setResultSetLoggingData(resultSetLoggingData);
|
||||
XTableColumnModel columnModel = (XTableColumnModel)table.getColumnModel();
|
||||
boolean isResultSetDataShown = columnModel.isColumnVisible(columnModel.getColumnByModelIndex(COLUMN_RS_LIFETIME));
|
||||
if(isResultSetDataShown) {
|
||||
@ -854,7 +851,9 @@ public class LoggerPane extends JPanel {
|
||||
}
|
||||
}
|
||||
};
|
||||
DebuggerRegistry.addSqlQueryDebugger(sqlQueryDebugger);
|
||||
debugger.setLoggingListener(loggingListener);
|
||||
} else {
|
||||
debugger.setLoggingListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -909,7 +908,7 @@ public class LoggerPane extends JPanel {
|
||||
"<th>Stack trace</th>" +
|
||||
"</tr>\n");
|
||||
for(QueryDebuggingInfo queryDebuggingInfo: queryDebuggingInfos) {
|
||||
DebuggerResultSetData resultSetData = queryDebuggingInfo.getSqlQueryDebuggerResultSetData();
|
||||
ResultSetLoggingData resultSetData = queryDebuggingInfo.getResultSetLoggingData();
|
||||
htmlSB.append("<tr>\n");
|
||||
htmlSB.append("<td>");
|
||||
htmlSB.append(queryDebuggingInfo.getQueryType());
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
*/
|
||||
package org.jooq.debug.console.remote;
|
||||
|
||||
import org.jooq.debug.DebuggerData;
|
||||
import org.jooq.debug.QueryLoggingData;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
@ -44,13 +44,13 @@ import org.jooq.debug.DebuggerData;
|
||||
@SuppressWarnings("serial")
|
||||
public class ClientDebugQueriesMessage implements Message {
|
||||
|
||||
private DebuggerData sqlQueryDebuggerData;
|
||||
private QueryLoggingData sqlQueryDebuggerData;
|
||||
|
||||
public ClientDebugQueriesMessage(DebuggerData sqlQueryDebuggerData) {
|
||||
public ClientDebugQueriesMessage(QueryLoggingData sqlQueryDebuggerData) {
|
||||
this.sqlQueryDebuggerData = sqlQueryDebuggerData;
|
||||
}
|
||||
|
||||
public DebuggerData getSqlQueryDebuggerData() {
|
||||
public QueryLoggingData getSqlQueryDebuggerData() {
|
||||
return sqlQueryDebuggerData;
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
*/
|
||||
package org.jooq.debug.console.remote;
|
||||
|
||||
import org.jooq.debug.DebuggerResultSetData;
|
||||
import org.jooq.debug.ResultSetLoggingData;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
@ -45,9 +45,9 @@ import org.jooq.debug.DebuggerResultSetData;
|
||||
public class ClientDebugResultSetMessage implements Message {
|
||||
|
||||
private int sqlQueryDebuggerDataID;
|
||||
private DebuggerResultSetData sqlQueryDebuggerResultSetData;
|
||||
private ResultSetLoggingData sqlQueryDebuggerResultSetData;
|
||||
|
||||
public ClientDebugResultSetMessage(int sqlQueryDebuggerDataID, DebuggerResultSetData sqlQueryDebuggerData) {
|
||||
public ClientDebugResultSetMessage(int sqlQueryDebuggerDataID, ResultSetLoggingData sqlQueryDebuggerData) {
|
||||
this.sqlQueryDebuggerDataID = sqlQueryDebuggerDataID;
|
||||
this.sqlQueryDebuggerResultSetData = sqlQueryDebuggerData;
|
||||
}
|
||||
@ -56,7 +56,7 @@ public class ClientDebugResultSetMessage implements Message {
|
||||
return sqlQueryDebuggerDataID;
|
||||
}
|
||||
|
||||
public DebuggerResultSetData getSqlQueryDebuggerResultSetData() {
|
||||
public ResultSetLoggingData getSqlQueryDebuggerResultSetData() {
|
||||
return sqlQueryDebuggerResultSetData;
|
||||
}
|
||||
|
||||
|
||||
@ -44,61 +44,45 @@ import java.io.ObjectOutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.jooq.debug.Debugger;
|
||||
import org.jooq.debug.DebuggerData;
|
||||
import org.jooq.debug.DebuggerRegistry;
|
||||
import org.jooq.debug.DebuggerRegistryListener;
|
||||
import org.jooq.debug.DebuggerResultSetData;
|
||||
import org.jooq.debug.LoggingListener;
|
||||
import org.jooq.debug.QueryLoggingData;
|
||||
import org.jooq.debug.ResultSetLoggingData;
|
||||
import org.jooq.debug.StatementExecutor;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class RemoteDebuggerClient {
|
||||
public class RemoteDebuggerClient implements Debugger {
|
||||
|
||||
private Socket socket;
|
||||
private ObjectOutputStream out;
|
||||
private final Object LOCK = new Object();
|
||||
|
||||
public RemoteDebuggerClient(String ip, int port) throws Exception {
|
||||
socket = new Socket(ip, port);
|
||||
out = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
|
||||
Thread thread = new Thread("SQL Remote Debugger Client on port " + port) {
|
||||
@Override
|
||||
public void run() {
|
||||
DebuggerRegistryListener debuggerRegisterListener = null;
|
||||
try {
|
||||
final ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
|
||||
debuggerRegisterListener = new DebuggerRegistryListener() {
|
||||
@Override
|
||||
public void notifyDebuggerListenersModified() {
|
||||
try {
|
||||
boolean isLogging = !DebuggerRegistry.getDebuggerList().isEmpty();
|
||||
out.writeObject(new ServerLoggingActivationMessage(isLogging));
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
DebuggerRegistry.addDebuggerRegisterListener(debuggerRegisterListener);
|
||||
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
|
||||
for(Message o; (o=(Message)in.readObject()) != null; ) {
|
||||
if(o instanceof ClientDebugQueriesMessage) {
|
||||
DebuggerData sqlQueryDebuggerData = ((ClientDebugQueriesMessage) o).getSqlQueryDebuggerData();
|
||||
for(Debugger debugger: DebuggerRegistry.getDebuggerList()) {
|
||||
debugger.debugQueries(sqlQueryDebuggerData);
|
||||
}
|
||||
} else if(o instanceof ClientDebugResultSetMessage) {
|
||||
ClientDebugResultSetMessage m = (ClientDebugResultSetMessage) o;
|
||||
int sqlQueryDebuggerDataID = m.getSqlQueryDebuggerDataID();
|
||||
DebuggerResultSetData clientDebugResultSetData = m.getSqlQueryDebuggerResultSetData();
|
||||
for(Debugger debugger: DebuggerRegistry.getDebuggerList()) {
|
||||
debugger.debugResultSet(sqlQueryDebuggerDataID, clientDebugResultSetData);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
|
||||
for(Message o; (o=(Message)in.readObject()) != null; ) {
|
||||
if(o instanceof ClientDebugQueriesMessage) {
|
||||
if(loggingListener != null) {
|
||||
QueryLoggingData sqlQueryDebuggerData = ((ClientDebugQueriesMessage) o).getSqlQueryDebuggerData();
|
||||
loggingListener.logQueries(sqlQueryDebuggerData);
|
||||
}
|
||||
} else if(o instanceof ClientDebugResultSetMessage) {
|
||||
if(loggingListener != null) {
|
||||
ClientDebugResultSetMessage m = (ClientDebugResultSetMessage) o;
|
||||
int sqlQueryDebuggerDataID = m.getSqlQueryDebuggerDataID();
|
||||
ResultSetLoggingData clientDebugResultSetData = m.getSqlQueryDebuggerResultSetData();
|
||||
loggingListener.logResultSet(sqlQueryDebuggerDataID, clientDebugResultSetData);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(debuggerRegisterListener != null) {
|
||||
DebuggerRegistry.removeDebuggerRegisterListener(debuggerRegisterListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -106,4 +90,54 @@ public class RemoteDebuggerClient {
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private LoggingListener loggingListener;
|
||||
|
||||
@Override
|
||||
public void setLoggingListener(LoggingListener loggingListener) {
|
||||
this.loggingListener = loggingListener;
|
||||
try {
|
||||
synchronized (LOCK) {
|
||||
out.writeObject(new ServerLoggingActivationMessage(loggingListener != null));
|
||||
out.flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoggingListener getLoggingListener() {
|
||||
return loggingListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExecutionSupported() {
|
||||
// TODO: implement
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementExecutor createStatementExecutor(String sql, int maxRSRowsParsing, int retainParsedRSDataRowCountThreshold) {
|
||||
// TODO: implement
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTableNames() {
|
||||
// TODO: implement
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTableColumnNames() {
|
||||
// TODO: implement
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
// TODO: implement
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -45,9 +45,11 @@ import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.jooq.debug.Debugger;
|
||||
import org.jooq.debug.DebuggerData;
|
||||
import org.jooq.debug.DebuggerRegistry;
|
||||
import org.jooq.debug.DebuggerResultSetData;
|
||||
import org.jooq.debug.LocalDebugger;
|
||||
import org.jooq.debug.LoggingListener;
|
||||
import org.jooq.debug.QueryLoggingData;
|
||||
import org.jooq.debug.ResultSetLoggingData;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
@ -88,38 +90,40 @@ public class RemoteDebuggerServer {
|
||||
Thread clientThread = new Thread("SQL Remote Debugger Server on port " + port) {
|
||||
@Override
|
||||
public void run() {
|
||||
Debugger sqlQueryDebugger = null;
|
||||
Debugger debugger = null;
|
||||
boolean isLogging = false;
|
||||
try {
|
||||
ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
|
||||
final ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
|
||||
sqlQueryDebugger = new Debugger() {
|
||||
@Override
|
||||
public synchronized void debugQueries(DebuggerData sqlQueryDebuggerData) {
|
||||
try {
|
||||
out.writeObject(new ClientDebugQueriesMessage(sqlQueryDebuggerData));
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public synchronized void debugResultSet(int sqlQueryDebuggerDataID, DebuggerResultSetData sqlQueryDebuggerResultSetData) {
|
||||
try {
|
||||
out.writeObject(new ClientDebugResultSetMessage(sqlQueryDebuggerDataID, sqlQueryDebuggerResultSetData));
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
// TODO: find how to pass a database descriptor for remote edition.
|
||||
debugger = new LocalDebugger(null);
|
||||
DebuggerRegistry.addSqlQueryDebugger(debugger);
|
||||
for(Message o; (o=(Message)in.readObject()) != null; ) {
|
||||
if(o instanceof ServerLoggingActivationMessage) {
|
||||
isLogging = ((ServerLoggingActivationMessage) o).isLogging();
|
||||
if(isLogging) {
|
||||
DebuggerRegistry.addSqlQueryDebugger(sqlQueryDebugger);
|
||||
debugger.setLoggingListener(new LoggingListener() {
|
||||
@Override
|
||||
public void logQueries(QueryLoggingData queryLoggingData) {
|
||||
try {
|
||||
out.writeObject(new ClientDebugQueriesMessage(queryLoggingData));
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void logResultSet(int sqlQueryDebuggerDataID, ResultSetLoggingData resultSetLoggingData) {
|
||||
try {
|
||||
out.writeObject(new ClientDebugResultSetMessage(sqlQueryDebuggerDataID, resultSetLoggingData));
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
DebuggerRegistry.removeSqlQueryDebugger(sqlQueryDebugger);
|
||||
debugger.setLoggingListener(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,8 +132,8 @@ public class RemoteDebuggerServer {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
if(sqlQueryDebugger != null) {
|
||||
DebuggerRegistry.removeSqlQueryDebugger(sqlQueryDebugger);
|
||||
if(debugger != null) {
|
||||
DebuggerRegistry.removeSqlQueryDebugger(debugger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user