/** * */ package net.sourceforge.sqlexplorer.dbproduct; import java.sql.CallableStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.TreeMap; import net.sourceforge.sqlexplorer.Messages; import net.sourceforge.sqlexplorer.dataset.DataSet; import net.sourceforge.sqlexplorer.dbproduct.DatabaseProduct.ExecutionResults; import net.sourceforge.sqlexplorer.parsers.NamedParameter; public final class ExecutionResultImpl implements ExecutionResults { // Current state - IE, which set of results we're currently looking for private enum State { PRIMARY_RESULTS, // We're providing the main results, from Statement.getResults() SECONDARY_RESULTS, // We're providing resultsets from Statement.getMoreResults() PARAMETER_RESULTS, // We're returning resultsets from output parameters OUTPUT_PARAMETERS, // We're returning a fake result set listing output parameters CLOSED // All done } /* * Temporary class used by nextDataSet() to collate parameters */ private class ParamValues { private NamedParameter param; private ArrayList<Integer> columnIndexes = new ArrayList<Integer>(); public ParamValues(NamedParameter param, int columnIndex) { super(); this.param = param; add(columnIndex); } public void add(int columnIndex) { this.columnIndexes.add(new Integer(columnIndex)); } } private State state = State.PRIMARY_RESULTS; private AbstractDatabaseProduct product; private Statement stmt; private LinkedList<NamedParameter> parameters; private int maxRows; private int paramColumnIndex; private Iterator<NamedParameter> paramIter; private int updateCount; private ResultSet currentResultSet; // calss name of hive statement,DO NOT modify the string of "HivePreparedStatement". private final String hiveStatementClassName = "HivePreparedStatement"; public ExecutionResultImpl(AbstractDatabaseProduct product, Statement stmt, boolean hasResults, LinkedList<NamedParameter> parameters, int maxRows) throws SQLException { super(); this.product = product; this.stmt = stmt; this.parameters = parameters; this.maxRows = maxRows; if (!hasResults) { state = State.SECONDARY_RESULTS; } } public DataSet nextDataSet() throws SQLException { // Close the current one if (currentResultSet != null) { currentResultSet.close(); currentResultSet = null; } // Anything more to do? if (state == State.CLOSED) { return null; } // Get the first set if (state == State.PRIMARY_RESULTS) { currentResultSet = stmt.getResultSet(); state = State.SECONDARY_RESULTS; if (currentResultSet != null) { return new DataSet(currentResultSet, null, maxRows); } } // While we have more secondary results (i.e. those that come directly from Statement but after the first // getResults()) while (state == State.SECONDARY_RESULTS) { // MOD msjian TDQ-5927, fix the "statement is not executing" error for SQLite. if ("org.sqlite.PrepStmt".equals(stmt.getClass().getName())) { return null; } // MOD qiongli TDQ-5907, HivePreparedStatement doesn't support method 'getMoreResults()'. // MOD xqliu 2014-03-18 // if the the connectoin type is hive, when call stmt.getMoreResults() will throw exception, so need to // judge the connection type first, if it is hive connection just call "updateCountState()", else call // stmt.getMoreResults() to decide to execute "currentResultSet = stmt.getResultSet()" or call // "updateCountState()" if (stmt.getClass().getName().contains(hiveStatementClassName)) { updateCountState(); } else if (stmt.getMoreResults()) { currentResultSet = stmt.getResultSet(); } else { updateCountState(); } // ~ xqliu 2014-03-18 } // Got one? Then exit if (currentResultSet != null) { this.updateCount += stmt.getUpdateCount(); return new DataSet(currentResultSet, null, maxRows); } // Look for output parameters which return resultsets if (state == State.PARAMETER_RESULTS && parameters != null) { CallableStatement stmt = (CallableStatement) this.stmt; if (paramIter == null) { paramIter = parameters.iterator(); paramColumnIndex = 1; } while (paramIter.hasNext()) { NamedParameter param = paramIter.next(); if (param.getDataType() == NamedParameter.DataType.CURSOR) { currentResultSet = product.getResultSet(stmt, param, paramColumnIndex); } paramColumnIndex++; if (currentResultSet != null) { return new DataSet(Messages.getString("DataSet.Cursor") + ' ' + param.getName(), currentResultSet, null, maxRows); } } } // Generate a dataset for output parameters state = State.CLOSED; if (parameters == null) { return null; } if (!(stmt instanceof CallableStatement)) { return null; } CallableStatement stmt = (CallableStatement) this.stmt; TreeMap<NamedParameter, ParamValues> params = new TreeMap<NamedParameter, ParamValues>(); int columnIndex = 1; int numValues = 0; for (NamedParameter param : parameters) { if (param.getDataType() != NamedParameter.DataType.CURSOR && param.isOutput()) { ParamValues pv = params.get(param); if (pv == null) { params.put(param, new ParamValues(param, columnIndex)); } else { pv.add(columnIndex); } numValues++; } columnIndex++; } if (numValues == 0) { return null; } Comparable[][] rows = new Comparable[numValues][2]; columnIndex = 1; int rowIndex = 0; for (ParamValues pv : params.values()) { int valueIndex = 1; for (Integer index : pv.columnIndexes) { Comparable[] row = rows[rowIndex++]; row[0] = pv.param.getName(); if (pv.columnIndexes.size() > 1) { row[0] = (pv.param.getName() + '[' + valueIndex + ']'); } else { row[0] = pv.param.getName(); } row[1] = stmt.getString(index); valueIndex++; } } return new DataSet(Messages.getString("DataSet.Parameters"), new String[] { Messages.getString("SQLExecution.ParameterName"), Messages.getString("SQLExecution.ParameterValue") }, rows); } /** * update the count or state. * * @throws SQLException */ private void updateCountState() throws SQLException { int updateCount = stmt.getUpdateCount(); if (updateCount != -1 && updateCount != 0) { this.updateCount += updateCount; } else { state = State.PARAMETER_RESULTS; } } public void close() throws SQLException { try { stmt.close(); } catch (SQLException e) { // Nothing } if (currentResultSet != null) { currentResultSet.close(); } } public int getUpdateCount() throws SQLException { return updateCount; } }