/*******************************************************************************
* Copyright (c) 2016 hangum.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* hangum - initial API and implementation
******************************************************************************/
package com.hangum.tadpole.rdb.core.editors.main.composite.plandetail;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import com.hangum.tadpole.engine.query.dao.mysql.InformationSchemaDAO;
import com.hangum.tadpole.engine.query.dao.mysql.TableDAO;
import com.hangum.tadpole.engine.sql.util.RDBTypeToJavaTypeUtils;
import com.hangum.tadpole.engine.sql.util.resultset.QueryExecuteResultDTO;
import com.hangum.tadpole.engine.sql.util.resultset.TadpoleResultSet;
import com.hangum.tadpole.engine.utils.RequestQuery;
import com.hangum.tadpole.rdb.core.dialog.dml.IndexInformationDialog;
import com.hangum.tadpole.rdb.core.dialog.dml.TableInformationDialog;
import com.hangum.tadpole.rdb.core.editors.main.composite.plandetail.oracle.OraclePlanDAO;
import com.hangum.tadpole.rdb.core.editors.main.composite.tail.PlanTailComposite;
/**
* Oracle plan composite
*
* @author hangum
*
*/
public class OraclePlanComposite extends AbstractPlanComposite {
/** Logger for this class. */
private static final Logger logger = Logger.getLogger(OraclePlanComposite.class);
private TreeViewer tvQueryPlan;
private List<OraclePlanDAO> listOraclePlanDao = new ArrayList<>();
/**
* Create the composite.
* @param parent
* @param style
*/
public OraclePlanComposite(Composite parent, int style, QueryExecuteResultDTO rsDAO) {
super(parent, style, rsDAO);
setLayout(new GridLayout(1, false));
Composite compositeBody = new Composite(this, SWT.NONE);
GridLayout gl_compositeHead = new GridLayout(2, false);
gl_compositeHead.verticalSpacing = 2;
gl_compositeHead.horizontalSpacing = 2;
gl_compositeHead.marginHeight = 0;
gl_compositeHead.marginWidth = 2;
compositeBody.setLayout(gl_compositeHead);
compositeBody.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
compositeBody.setLayout(new GridLayout(1, false));
tvQueryPlan = new TreeViewer(compositeBody, SWT.BORDER | SWT.FULL_SELECTION);
Tree tree = tvQueryPlan.getTree();
tree.setLinesVisible(true);
tree.setHeaderVisible(true);
tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
tree.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent event) {
if (event.keyCode == SWT.F4) {
IStructuredSelection is = (IStructuredSelection) tvQueryPlan.getSelection();
OraclePlanDAO selElement = (OraclePlanDAO)is.getFirstElement();
openInformationDialog(selElement);
}
}
});
tvQueryPlan.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
IStructuredSelection is = (IStructuredSelection)event.getSelection();
OraclePlanDAO selElement = (OraclePlanDAO)is.getFirstElement();
openInformationDialog(selElement);
}
});
Composite compositeBtn = new Composite(compositeBody, SWT.NONE);
compositeBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
GridLayout gl_compositeBtn = new GridLayout(4, false);
gl_compositeBtn.verticalSpacing = 2;
gl_compositeBtn.horizontalSpacing = 2;
gl_compositeBtn.marginWidth = 0;
gl_compositeBtn.marginHeight = 2;
compositeBtn.setLayout(gl_compositeBtn);
compositeTail = new PlanTailComposite(this, compositeBtn, SWT.NONE);
compositeTail.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2));
GridLayout gl_compositeResult = new GridLayout(1, false);
gl_compositeResult.verticalSpacing = 2;
gl_compositeResult.horizontalSpacing = 2;
gl_compositeResult.marginHeight = 0;
gl_compositeResult.marginWidth = 2;
compositeTail.setLayout(gl_compositeResult);
}
/**
* 플랜뷰에서 F4를 누르거나 더블클릭했을때 관련 오브젝트의 상세 내역을 표시한다.
* @param selElement
*/
private void openInformationDialog(OraclePlanDAO selElement) {
if (StringUtils.equalsIgnoreCase("TABLE", selElement.getObjectType())){
TableDAO tableDao = new TableDAO();
String temp = selElement.getName();
String object[] = StringUtils.split(temp, '.');
if (object.length > 1){
tableDao.setSchema_name(object[0]);
String obj = object[1];
String tbl[] = StringUtils.split(obj, '(');
if (tbl.length > 1){
tableDao.setSysName(tbl[0]);
tableDao.setTable_name(tbl[0]);
}else{
tableDao.setSysName(obj);
tableDao.setTable_name(obj);
}
}else{
tableDao.setSysName(temp);
tableDao.setTable_name(temp);
}
new TableInformationDialog(getShell(), false, getRsDAO().getUserDB(), tableDao).open();
}else if (StringUtils.startsWithIgnoreCase(selElement.getObjectType(), "INDEX" )){
InformationSchemaDAO indexDao = new InformationSchemaDAO();
String temp = selElement.getName();
String object[] = StringUtils.split(temp, '.');
if (object.length > 1){
indexDao.setTABLE_SCHEMA(object[0]);
String obj = object[1];
String tbl[] = StringUtils.split(obj, '(');
if (tbl.length > 1){
indexDao.setINDEX_NAME(tbl[0]);
}else{
indexDao.setINDEX_NAME(obj);
}
}else{
indexDao.setINDEX_NAME(temp);
}
new IndexInformationDialog(getShell(), false, getRsDAO().getUserDB(), indexDao).open();
}
}
public void setQueryPlanData(RequestQuery reqQuery, QueryExecuteResultDTO rsDAO) {
if(tvQueryPlan.getTree().getColumnCount() == 0) createTreeColumn(rsDAO);
listOraclePlanDao.clear();
this.reqQuery = reqQuery;
this.rsDAO = rsDAO;
// table data를 생성한다.
final TadpoleResultSet trs = rsDAO.getDataList();
List<Map<Integer, Object>> listObj = trs.getData();
for (Map<Integer, Object> map : listObj) {
OraclePlanDAO dao = new OraclePlanDAO();
dao.setOperation(""+map.get(1));
dao.setName(""+map.get(2));
dao.setCost(""+map.get(3));
dao.setRows(""+map.get(4));
dao.setBytes(map.get(5)==null?"":""+map.get(5));
dao.setPos(Integer.parseInt(map.get(6)==null?"0":""+map.get(6)));
dao.setFilter(map.get(7)==null?"":""+map.get(7));
dao.setAccess(map.get(8)==null?"":""+map.get(8));
dao.setObjectType(map.get(9)==null?"":""+map.get(9));
if(listOraclePlanDao.isEmpty()) {
listOraclePlanDao.add(dao);
} else {
addChild(listOraclePlanDao, dao);
}
}
tvQueryPlan.setLabelProvider(new OracleLabelProvider());
tvQueryPlan.setContentProvider(new OraclePlanContentProvider());
// 쿼리를 설정한 사용자가 설정 한 만큼 보여준다.
tvQueryPlan.setInput(listOraclePlanDao);
tvQueryPlan.expandAll();
compositeTail.execute(getTailResultMsg());
}
private void addChild(List<OraclePlanDAO> list, OraclePlanDAO dao){
int size=0;
for(OraclePlanDAO alOraclePlan : list) {
if(alOraclePlan.getListChildren().size() > 0) {
addChild(alOraclePlan.getListChildren(), dao);
return;
}
size++;
if (list.size() > size) continue;
if((dao.getPos()-1) == alOraclePlan.getPos()) {
alOraclePlan.getListChildren().add(dao);
return;
}
}
list.add(dao);
return;
}
/**
* crate tree column
* @param rsDAO
*/
private void createTreeColumn(QueryExecuteResultDTO rsDAO) {
Map<Integer, String> mapColumn = rsDAO.getColumnLabelName();
for (int i=1; i< mapColumn.size(); i++) {
TreeViewerColumn treeViewerColumn = new TreeViewerColumn(tvQueryPlan, SWT.NONE);
TreeColumn trclmnUrl = treeViewerColumn.getColumn();
if( RDBTypeToJavaTypeUtils.isNumberType(rsDAO.getColumnType().get(i)) ) {
trclmnUrl.setAlignment(SWT.RIGHT);
trclmnUrl.setWidth(80);
}else{
trclmnUrl.setWidth(300);
}
trclmnUrl.setText(mapColumn.get(i));
}
}
}
/**
* content provider
*
* @author hangum
*
*/
class OraclePlanContentProvider implements ITreeContentProvider {
@Override
public void dispose() {
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
@Override
public Object[] getElements(Object inputElement) {
List<OraclePlanDAO> listOraclePlanDao = (List)inputElement;
return listOraclePlanDao.toArray();
}
@Override
public Object[] getChildren(Object parentElement) {
OraclePlanDAO oraclePlanDao = (OraclePlanDAO)parentElement;
return oraclePlanDao.getListChildren().toArray();
}
@Override
public Object getParent(Object element) {
return null;
}
@Override
public boolean hasChildren(Object element) {
OraclePlanDAO oraclePlanDao = (OraclePlanDAO)element;
return oraclePlanDao.getListChildren().isEmpty()?false:true;
}
}
/**
* label provider
*
* @author hangum
*
*/
class OracleLabelProvider extends LabelProvider implements ITableLabelProvider {
@Override
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
@Override
public String getColumnText(Object element, int columnIndex) {
OraclePlanDAO dao = (OraclePlanDAO)element;
switch(columnIndex) {
case 0: return dao.getOperation();
case 1: return dao.getName();
case 2: return dao.getCost();
case 3: return dao.getRows();
case 4: return dao.getBytes();
case 5: return ""+dao.getPos();
case 6: return ""+dao.getAccess();
case 7: return ""+dao.getFilter();
case 8: return ""+dao.getObjectType();
}
return "*** not set column ***";
}
}