/*
* Copyright 2015 the original author or authors.
* @https://github.com/scouter-project/scouter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package scouter.client.xlog.dialog;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import scouter.client.model.TextProxy;
import scouter.client.model.XLogData;
import scouter.client.popup.SQLFormatDialog;
import scouter.client.util.UIUtil;
import scouter.lang.step.HashedMessageStep;
import scouter.lang.step.SqlStep;
import scouter.lang.step.SqlStep3;
import scouter.lang.step.Step;
import scouter.lang.step.StepEnum;
import scouter.lang.step.StepSingle;
import scouter.util.FormatUtil;
import scouter.util.Hexa32;
public class XlogSummarySQLDialog extends Dialog {
private Table sqlTable;
private Table bindTable;
private Step[] steps;
private XLogData xperf;
private HashMap<Integer, SQLSumData> sqlMap = new HashMap<Integer, SQLSumData>();
public XlogSummarySQLDialog(Shell shell, Step[] steps, XLogData xperf) {
super(shell);
this.xperf = xperf;
this.steps = steps;
}
protected Control createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
FillLayout layout = new FillLayout();
container.setLayout(layout);
SashForm sashVertForm = new SashForm(container, SWT.VERTICAL);
sashVertForm.SASH_WIDTH = 3;
initSQLTable(sashVertForm);
initBindTable(sashVertForm);
sashVertForm.setWeights(new int [] {55, 45});
processSqlData();
displaySQLSumData();
return container;
}
private void initSQLTable(Composite parent){
sqlTable = new Table(parent, SWT.BORDER | SWT.FULL_SELECTION);
TableColumn tableColumn = new TableColumn(sqlTable, SWT.RIGHT);
tableColumn.setText("Execs");
tableColumn.setWidth(80);
tableColumn = new TableColumn(sqlTable, SWT.RIGHT);
tableColumn.setText("Binds");
tableColumn.setWidth(80);
tableColumn = new TableColumn(sqlTable, SWT.RIGHT);
tableColumn.setText("Exec Time");
tableColumn.setWidth(80);
tableColumn = new TableColumn(sqlTable, SWT.RIGHT);
tableColumn.setText("Fetch Time");
tableColumn.setWidth(80);
tableColumn = new TableColumn(sqlTable, SWT.RIGHT);
tableColumn.setText("Total Rows");
tableColumn.setWidth(80);
tableColumn = new TableColumn(sqlTable, SWT.LEFT);
tableColumn.setText("SQL Text");
tableColumn.setWidth(600);
sqlTable.setHeaderVisible(true);
sqlTable.setVisible(true);
sqlTable.addSelectionListener(new SelectionListener(){
public void widgetDefaultSelected(SelectionEvent event) {
}
@SuppressWarnings("unchecked")
public void widgetSelected(SelectionEvent event) {
bindTable.clearAll();
bindTable.setItemCount(0);
TableItem item = (TableItem)event.item;
if(item == null)
return;
Integer hash = (Integer)item.getData();
ArrayList<BindSumData> list = getLBindSumDataList(hash.intValue());
Collections.sort(list, new BindSumDataComp());
String sqlText = sqlMap.get(hash).sqlText;
TableItem bindItem;
for(BindSumData value : list){
bindItem = new TableItem(bindTable, SWT.BORDER);
bindItem.setText(value.toTableInfo());
bindItem.setData(sqlText);
}
}
});
}
private void initBindTable(Composite parent){
bindTable = new Table(parent, SWT.BORDER | SWT.FULL_SELECTION);
TableColumn tableColumn = new TableColumn(bindTable, SWT.RIGHT);
tableColumn.setText("Execs");
tableColumn.setWidth(80);
tableColumn = new TableColumn(bindTable, SWT.RIGHT);
tableColumn.setText("Exec Time");
tableColumn.setWidth(80);
tableColumn = new TableColumn(bindTable, SWT.RIGHT);
tableColumn.setText("Fetch Time");
tableColumn.setWidth(80);
tableColumn = new TableColumn(bindTable, SWT.RIGHT);
tableColumn.setText("Total Rows");
tableColumn.setWidth(80);
tableColumn = new TableColumn(bindTable, SWT.LEFT);
tableColumn.setText("Bind Variables");
tableColumn.setWidth(600);
bindTable.setHeaderVisible(true);
bindTable.setVisible(true);
bindTable.setToolTipText("Please double click on in order to view the complete SQL statement");
bindTable.addMouseListener(new MouseListener(){
public void mouseDoubleClick(MouseEvent event) {
TableItem [] items = bindTable.getSelection();
if(items.length == 0){
return;
}
TableItem item = items[0];
String sqlText = (String)item.getData();
String binds = item.getText(4);
new SQLFormatDialog().show(sqlText, null, binds);
}
@Override
public void mouseDown(MouseEvent event) {
}
@Override
public void mouseUp(MouseEvent event) {
}
});
}
protected void displaySQLSumData(){
sqlTable.clearAll();
sqlTable.setItemCount(0);
ArrayList<SQLSumData> list = getLSQLSumDataList();
Collections.sort(list, new SQLSumDataComp());
TableItem item;
for(SQLSumData value : list){
item = new TableItem(sqlTable, SWT.BORDER);
item.setText(value.toTableInfo());
item.setData(new Integer(value.hash));
}
}
protected void processSqlData(){
StepSingle stepSingle;
SqlStep sql;
HashedMessageStep message;
SQLSumData sqlSumData = null;
BindSumData bindSumData = null;
String bindParam;
for (int i = 0; i < steps.length; i++) {
stepSingle = (StepSingle)steps[i];
switch(stepSingle.getStepType()){
case StepEnum.SQL:
case StepEnum.SQL2:
case StepEnum.SQL3:
sql = (SqlStep)stepSingle;
sqlSumData = sqlMap.get(sql.hash);
if(sqlSumData == null){
sqlSumData = new SQLSumData();
sqlSumData.hash = sql.hash;
sqlSumData.sqlText = TextProxy.sql.getText(sql.hash);
sqlMap.put(sql.hash, sqlSumData);
}
sqlSumData.execs++;
sqlSumData.execTime += sql.elapsed;
bindSumData = sqlSumData.bindMap.get(sql.param);
if(bindSumData == null){
sqlSumData.binds++;
bindSumData = new BindSumData();
if(sql.param == null){
bindParam = "[No Value]";
}else{
bindParam = sql.param;
}
bindSumData.bindText = bindParam;
sqlSumData.bindMap.put(bindParam, bindSumData);
}
bindSumData.execs++;
bindSumData.execTime += sql.elapsed;
if(StepEnum.SQL3 == stepSingle.getStepType()){
int updatedCount = ((SqlStep3)stepSingle).updated;
if (updatedCount > SqlStep3.EXECUTE_RESULT_SET) {
sqlSumData.totalRows += updatedCount;
bindSumData.totalRows += updatedCount;
}
}
break;
case StepEnum.HASHED_MESSAGE:
message = (HashedMessageStep)stepSingle;
if(!"RESULT-SET-FETCH".equals(TextProxy.hashMessage.getText(message.hash))){
continue;
}
if(sqlSumData != null){
sqlSumData.fetchTime += message.time;
sqlSumData.totalRows += message.value;
}
if(bindSumData != null){
bindSumData.fetchTime += message.time;
bindSumData.totalRows += message.value;
}
break;
}
}
}
private ArrayList<SQLSumData> getLSQLSumDataList(){
ArrayList<SQLSumData> list = new ArrayList<SQLSumData>();
Iterator<SQLSumData> itor = sqlMap.values().iterator();
while(itor.hasNext()){
list.add(itor.next());
}
return list;
}
private ArrayList<BindSumData> getLBindSumDataList(int hash){
ArrayList<BindSumData> list = new ArrayList<BindSumData>();
SQLSumData sqlSumData = sqlMap.get(hash);
if(sqlSumData == null){
return null;
}
HashMap<String, BindSumData> bindMap = sqlSumData.bindMap;
Iterator<BindSumData> itor = bindMap.values().iterator();
while(itor.hasNext()){
list.add(itor.next());
}
return list;
}
@Override
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
newShell.setText(new StringBuilder(100).append("SQL Statistics Summary-").append(TextProxy.service.getText(xperf.p.service)).append('(').append(Hexa32.toString32(xperf.p.txid)).append(")-").append(FormatUtil.print(xperf.p.elapsed, "#,##0")).append("ms").toString());
}
@Override
protected boolean isResizable() {
return true;
}
@Override
protected Control createButtonBar(Composite parent){
return null;
}
@Override
protected void initializeBounds(){
int[] size = UIUtil.getScreenSize();
this.getShell().setBounds((size[0]/2)-400, (size[1]/2)-200, 800, 400);
}
private class SQLSumData {
public int execs = 0;
public int binds = 0;
public int execTime = 0;
public int fetchTime = 0;
public int totalRows = 0;
public String sqlText = null;
public int hash = 0;
public HashMap<String, BindSumData> bindMap = new HashMap<String, BindSumData>();
public String[] toTableInfo(){
String [] values = new String[6];
values[0] = FormatUtil.print(execs, "#,##0");
values[1] = FormatUtil.print(binds, "#,##0");
values[2] = FormatUtil.print(execTime, "#,##0");
values[3] = FormatUtil.print(fetchTime, "#,##0");
values[4] = FormatUtil.print(totalRows, "#,##0");
values[5] = sqlText;
return values;
}
}
private class BindSumData {
public int execs = 0;
public int execTime = 0;
public int fetchTime = 0;
public int totalRows = 0;
public String bindText = null;
public String[] toTableInfo(){
String [] values = new String[6];
values[0] = FormatUtil.print(execs, "#,##0");
values[1] = FormatUtil.print(execTime, "#,##0");
values[2] = FormatUtil.print(fetchTime, "#,##0");
values[3] = FormatUtil.print(totalRows, "#,##0");
values[4] = bindText;
return values;
}
}
private class SQLSumDataComp implements Comparator<SQLSumData>{
public int compare(SQLSumData o1, SQLSumData o2) {
if(o1.execTime > o2.execTime)
return -1;
else if(o1.execTime < o2.execTime)
return 1;
return 0;
}
}
private class BindSumDataComp implements Comparator<BindSumData>{
public int compare(BindSumData o1, BindSumData o2) {
if(o1.execTime > o2.execTime)
return -1;
else if(o1.execTime < o2.execTime)
return 1;
return 0;
}
}
}