/** * Closes all resources (statement, result set) held by this SqlStatement. * * <p>If any of them fails, wraps them in a {@link RuntimeException} describing the high-level * operation which this statement was performing. No further error-handling is required to produce * a descriptive stack trace, unless you want to absorb the error. */ public void close() { if (haveSemaphore) { haveSemaphore = false; querySemaphore.leave(); } // According to the JDBC spec, closing a statement automatically closes // its result sets, and closing a connection automatically closes its // statements. But let's be conservative and close everything // explicitly. Statement statement = null; SQLException ex = null; if (resultSet != null) { try { statement = resultSet.getStatement(); resultSet.close(); } catch (SQLException e) { ex = e; } finally { resultSet = null; } } if (statement != null) { try { statement.close(); } catch (SQLException e) { if (ex != null) { ex = e; } } } if (jdbcConnection != null) { try { jdbcConnection.close(); } catch (SQLException e) { if (ex != null) { ex = e; } } finally { jdbcConnection = null; } } if (ex != null) { throw Util.newError(ex, locus.message + "; sql=[" + sql + "]"); } long endTime = System.currentTimeMillis(); long totalMs = endTime - startTimeMillis; String status = ", exec+fetch " + totalMs + " ms, " + rowCount + " rows"; locus.execution.getQueryTiming().markFull(TIMING_NAME + locus.component, totalMs); RolapUtil.SQL_LOGGER.debug(id + ": " + status); if (RolapUtil.LOGGER.isDebugEnabled()) { RolapUtil.LOGGER.debug(locus.component + ": done executing sql [" + sql + "]" + status); } locus .getServer() .getMonitor() .sendEvent( new SqlStatementEndEvent(endTime, id, locus, sql, getPurpose(), rowCount, false, null)); }
/** Executes the current statement, and handles any SQLException. */ public void execute() { assert state == State.FRESH : "cannot re-execute"; state = State.ACTIVE; String status = "failed"; Statement statement = null; try { this.jdbcConnection = dataSource.getConnection(); querySemaphore.enter(); haveSemaphore = true; // Trace start of execution. if (RolapUtil.SQL_LOGGER.isDebugEnabled()) { StringBuilder sqllog = new StringBuilder(); sqllog.append(id).append(": ").append(locus.component).append(": executing sql ["); if (sql.indexOf('\n') >= 0) { // SQL appears to be formatted as multiple lines. Make it // start on its own line. sqllog.append("\n"); } sqllog.append(sql); sqllog.append(']'); RolapUtil.SQL_LOGGER.debug(sqllog.toString()); } // Execute hook. RolapUtil.ExecuteQueryHook hook = RolapUtil.getHook(); if (hook != null) { hook.onExecuteQuery(sql); } startTimeNanos = System.nanoTime(); startTimeMillis = System.currentTimeMillis(); if (resultSetType < 0 || resultSetConcurrency < 0) { statement = jdbcConnection.createStatement(); } else { statement = jdbcConnection.createStatement(resultSetType, resultSetConcurrency); } if (maxRows > 0) { statement.setMaxRows(maxRows); } // First make sure to register with the execution instance. locus.execution.registerStatement(locus, statement); locus .getServer() .getMonitor() .sendEvent( new SqlStatementStartEvent( startTimeMillis, id, locus, sql, getPurpose(), getCellRequestCount())); this.resultSet = statement.executeQuery(sql); // skip to first row specified in request this.state = State.ACTIVE; if (firstRowOrdinal > 0) { if (resultSetType == ResultSet.TYPE_FORWARD_ONLY) { for (int i = 0; i < firstRowOrdinal; ++i) { if (!this.resultSet.next()) { this.state = State.DONE; break; } } } else { if (!this.resultSet.absolute(firstRowOrdinal)) { this.state = State.DONE; } } } long timeMillis = System.currentTimeMillis(); long timeNanos = System.nanoTime(); final long executeNanos = timeNanos - startTimeNanos; final long executeMillis = executeNanos / 1000000; Util.addDatabaseTime(executeMillis); status = ", exec " + executeMillis + " ms"; locus .getServer() .getMonitor() .sendEvent( new SqlStatementExecuteEvent(timeMillis, id, locus, sql, getPurpose(), executeNanos)); // Compute accessors. They ensure that we use the most efficient // method (e.g. getInt, getDouble, getObject) for the type of the // column. Even if you are going to box the result into an object, // it is better to use getInt than getObject; the latter might // return something daft like a BigDecimal (does, on the Oracle JDBC // driver). accessors.clear(); for (Type type : guessTypes()) { accessors.add(createAccessor(accessors.size(), type)); } } catch (Throwable e) { status = ", failed (" + e + ")"; Util.close(resultSet, statement, jdbcConnection); if (haveSemaphore) { haveSemaphore = false; querySemaphore.leave(); } if (e instanceof Error) { throw (Error) e; } else { throw handle(e); } } finally { RolapUtil.SQL_LOGGER.debug(id + ": " + status); if (RolapUtil.LOGGER.isDebugEnabled()) { RolapUtil.LOGGER.debug(locus.component + ": executing sql [" + sql + "]" + status); } } }