/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.datatools.connectivity.ui.plan; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.datatools.sqltools.core.DatabaseIdentifier; import org.eclipse.datatools.sqltools.core.SQLDevToolsConfiguration; import org.eclipse.datatools.sqltools.core.SQLToolsFacade; import org.eclipse.datatools.sqltools.core.services.ConnectionService; import org.eclipse.datatools.sqltools.sql.parser.ParsingResult; import org.eclipse.datatools.sqltools.sqleditor.ISQLEditorActionConstants; import org.eclipse.datatools.sqltools.sqleditor.SQLEditor; import org.eclipse.datatools.sqltools.sqleditor.plan.BaseExplainAction; import org.eclipse.datatools.sqltools.sqleditor.plan.Images; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorActionDelegate; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.texteditor.IUpdate; import org.teiid.datatools.connectivity.ui.Activator; import org.teiid.datatools.connectivity.ui.Messages; import org.teiid.datatools.views.ExecutionPlanView; public class TeiidExplainSQLActionDelegate extends BaseExplainAction implements IEditorActionDelegate, ISelectionChangedListener, IUpdate { protected SQLEditor _sqlEditor; public TeiidExplainSQLActionDelegate() { String title = Messages.getString("TeiidExplainSQLActionDelegate.title"); //$NON-NLS-1$ String tooltip = Messages.getString("TeiidExplainSQLActionDelegate.tooltip"); //$NON-NLS-1$ setText(title); setToolTipText(tooltip); setImageDescriptor(Images.DESC_EXPLAIN_SQL); setActionDefinitionId(ISQLEditorActionConstants.EXPLAIN_SQL_ACTION_ID); } public void setActiveEditor( SQLEditor targetEditor ) { _sqlEditor = targetEditor; targetEditor.getSelectionProvider().addSelectionChangedListener(this); update(); } @Override public void update() { String sql = getSQLStatements(); setEnabled(_sqlEditor != null && (_sqlEditor.isConnected()) && super.canBeEnabled() && (sql != null && sql.length() > 0)); } @Override public DatabaseIdentifier getDatabaseIdentifier() { return _sqlEditor == null ? null : _sqlEditor.getDatabaseIdentifier(); } @Override public String getSQLStatements() { if (_sqlEditor == null) { return null; } String selectedSQL = _sqlEditor.getSelectedText(); if (selectedSQL != null && !selectedSQL.isEmpty()) { return SQLToolsFacade.getDBHelper(getDatabaseIdentifier()).preprocessSQLScript(selectedSQL); } return getCurrentStatements(); } private String getCurrentStatements() { String selectedText = null; IDocument doc = _sqlEditor.getDocumentProvider().getDocument(_sqlEditor.getEditorInput()); ITextSelection selection = (ITextSelection)_sqlEditor.getSelectionProvider().getSelection(); int selectionLine = selection.getStartLine(); try { IRegion lineInfo = doc.getLineInformation(selectionLine); selectedText = doc.get(lineInfo.getOffset(), lineInfo.getLength()); } catch (BadLocationException ex) { return null; } return SQLToolsFacade.getDBHelper(getDatabaseIdentifier()).preprocessSQLScript(selectedText); } /** * Sets the focus to the editor after the execution plan is shown */ @Override public Runnable getPostRun() { Runnable postRun = new Runnable() { @Override public void run() { _sqlEditor.getEditorSite().getPage().activate(_sqlEditor); } }; return postRun; } /** * Returns the variable declarations in the SQL Editor */ @Override protected HashMap getVariableDeclarations() { ITextSelection _selection = (ITextSelection)_sqlEditor.getSelectionProvider().getSelection(); int start = 0; int length = 0; if (_selection == null) { _selection = (ITextSelection)_sqlEditor.getSelectionProvider().getSelection(); } // get the offset of the selection if (_selection != null && !_selection.isEmpty()) { start = _selection.getOffset(); length = _selection.getLength(); if (length < 0) { length = -length; start -= length; } } // when user selects a range int offset = length > 0 ? start + 1 : start; IDocument document = _sqlEditor.getDocumentProvider().getDocument(_sqlEditor.getEditorInput()); ParsingResult result = _sqlEditor.getParsingResult(); HashMap variables = new HashMap(); if (result != null) { variables = result.getVariables(document, offset); HashMap sp_params = result.getParameters(document, offset); variables.putAll(sp_params); } return variables; } /** * Updates the action when selection changes * * @param event */ @Override public void selectionChanged( SelectionChangedEvent event ) { if (event.getSelection() instanceof ITextSelection) { update(); } } @Override public void setActiveEditor( IAction action, IEditorPart targetEditor ) { setActiveEditor((SQLEditor)targetEditor); } @Override public void run() { if (!isEnabled()) { return; } // Get SQL from the Editor String sql = getSQLStatements(); // Establish Connection to run the plan Query establishConnection(); // Get the Teiid Execution Plan String planStr = null; try { planStr = getExecutionPlan(_conn, sql); } catch (SQLException e1) { String message = Messages.getString("TeiidExplainSQLActionDelegate.getPlanError"); //$NON-NLS-1$ IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, e1); Activator.getDefault().getLog().log(status); // Show Error Dialog, then exit Shell shell = Activator.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(); MessageDialog.openInformation(shell, Messages.getString("TeiidExplainSQLActionDelegate.getPlanErrorDialog.title"), //$NON-NLS-1$ Messages.getString("TeiidExplainSQLActionDelegate.getPlanErrorDialog.msg")); //$NON-NLS-1$ handleEnd(_conn); } // Re-direct to the Teiid Execution Plan View, and update with results IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); IViewPart viewPart = null; try { if (window != null) { viewPart = window.getActivePage().showView(ExecutionPlanView.VIEW_ID); if (viewPart instanceof ExecutionPlanView) { String panelDescription = org.teiid.datatools.connectivity.ui.Messages.getString("TeiidExplainSQLActionDelegate.panelDescription"); //$NON-NLS-1$ ((ExecutionPlanView)viewPart).updateContents(panelDescription, sql, planStr); } } } catch (PartInitException e) { String message = org.teiid.datatools.connectivity.ui.Messages.getString("TeiidExplainSQLActionDelegate.initViewError"); //$NON-NLS-1$ IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, e); Activator.getDefault().getLog().log(status); } // Closes the connection handleEnd(_conn); } private void establishConnection() { if (_conn == null) { String profileName = _sqlEditor.getDatabaseIdentifier().getProfileName(); String dbName = _sqlEditor.getDatabaseIdentifier().getDBname(); final SQLDevToolsConfiguration config = SQLToolsFacade.getConfigurationByProfileName(profileName); final ConnectionService conService = config.getConnectionService(); _conn = conService.createConnection(profileName, dbName); } } private String getExecutionPlan( Connection sqlConnection, String sql ) throws SQLException { String executionPlan = null; if (sql == null || sql.length() == 0) { throw new SQLException("An SQL statement is required to retrieve the execution plan"); //$NON-NLS-1$ } Statement stmt = sqlConnection.createStatement(); stmt.execute("SET NOEXEC ON"); //$NON-NLS-1$ stmt.execute("SET SHOWPLAN DEBUG"); //$NON-NLS-1$ stmt.executeQuery(sql); ResultSet planRs = stmt.executeQuery("SHOW PLAN"); //$NON-NLS-1$ planRs.next(); executionPlan = planRs.getString("PLAN_XML"); //$NON-NLS-1$ stmt.execute("SET NOEXEC OFF"); //$NON-NLS-1$ planRs.close(); stmt.close(); return executionPlan; } @Override public void run( IAction action ) { } @Override public void selectionChanged( IAction action, ISelection selection ) { if (selection instanceof ITextSelection) { update(); } } }