ro.nextreports.engine.queryexec.QueryExecutor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nextreports-engine Show documentation
Show all versions of nextreports-engine Show documentation
NextReports Engine is a lightweight Java platform development library which
can be used to run NextReports inside your applications.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 ro.nextreports.engine.queryexec;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.sql.CallableStatement;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.io.Serializable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import ro.nextreports.engine.querybuilder.IdNameRenderer;
import ro.nextreports.engine.querybuilder.sql.dialect.CSVDialect;
import ro.nextreports.engine.querybuilder.sql.dialect.ConnectionUtil;
import ro.nextreports.engine.querybuilder.sql.dialect.Dialect;
import ro.nextreports.engine.querybuilder.sql.dialect.DialectException;
import ro.nextreports.engine.querybuilder.sql.dialect.OracleDialect;
import ro.nextreports.engine.querybuilder.sql.dialect.SQLiteDialect;
import ro.nextreports.engine.queryexec.util.StringUtil;
import ro.nextreports.engine.util.DialectUtil;
import ro.nextreports.engine.util.ParameterUtil;
import ro.nextreports.engine.util.QueryUtil;
/**
* Interruptible Database Queries
*
* This class defines the executeQuery()
method, with posibility
* to interrup the database query, which is similar to Statement.executeQuery()
* method. The difference is that this method can be interrupted by another thread.
*
* @author Decebal Suiu
*/
public class QueryExecutor implements Runnable {
public static final int DEFAULT_TIMEOUT = 20;
public static final int DEFAULT_MAX_ROWS = 100;
public static final String EQUAL = "=";
public static final String NOT_EQUAL = "<>";
public static final String GREATER = ">";
public static final String GREATER_EQUAL = ">=";
public static final String LESS = "<";
public static final String LESS_EQUAL = "<=";
public static final String LIKE = "LIKE";
public static final String NOT_LIKE = "NOT LIKE";
public static final String IN = "IN";
public static final String NOT_IN = "NOT IN";
public static final String BETWEEN = "BETWEEN";
public static final String AND = "AND";
public static final String NOT = "NOT";
private static Log LOG = LogFactory.getLog(QueryExecutor.class);
private Query query;
private Map parameters = new HashMap();
private Map parameterValues;
private List parameterNames = new ArrayList();
private Connection conn;
private int timeout = DEFAULT_TIMEOUT;
private int maxRows = DEFAULT_MAX_ROWS;
private Thread worker;
private final InputWrapper inputWrapper;
private final ResultWrapper resultWrapper;
private volatile boolean cancelRequest;
private volatile boolean closeRequest;
private int outputParameterPosition = -1;
private boolean computeCount = false;
private boolean check = true;
private boolean isCsv = false;
private Map statementParameters = new HashMap();
// check = false when we want to run a parameter sql query at runtime
public QueryExecutor(Query query, Map parameters,
Map parameterValues, Connection conn, boolean computeCount, boolean check, boolean isCsv) throws QueryException {
processIgnoreParameters(query, parameters, parameterValues);
// check inputs!!!
if (check) {
checkInputs(query, parameters, parameterValues, conn);
}
this.query = query;
this.conn = conn;
this.parameterNames = query.parameterNames;
this.parameters = parameters;
this.parameterValues = parameterValues;
this.computeCount = computeCount;
this.check = check;
this.isCsv = isCsv;
inputWrapper = new InputWrapper();
resultWrapper = new ResultWrapper();
worker = new Thread(this, getClass().getSimpleName());
worker.start();
}
public QueryExecutor(Query query, Map parameters,
Map parameterValues, Connection conn, boolean computeCount) throws QueryException {
this(query, parameters, parameterValues, conn, computeCount, true, false);
}
public QueryExecutor(Query query, Map parameters,
Map parameterValues, Connection conn) throws QueryException {
this(query, parameters, parameterValues, conn, false);
}
public QueryExecutor(Query query, Connection conn) throws QueryException {
this(query, new HashMap(), new HashMap(), conn);
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public int getMaxRows() {
return maxRows;
}
public void setMaxRows(int maxRows) {
this.maxRows = maxRows;
}
public List getParameterNames() {
return parameterNames;
}
/**
* Execute the query.
* @return query result
* @throws QueryException query exception
* @throws InterruptedException interrupted exception
*/
public synchronized QueryResult execute() throws QueryException, InterruptedException {
// create query string
String queryString = createQueryString();
PreparedStatement countPstmt = null;
if (computeCount) {
try {
// count statement
String countQueryString = "SELECT COUNT(*) FROM (" + queryString + ") A";
if (isCsv) {
// csv jdbc driver does not support sub-select
countQueryString = getCsvCountQuery(queryString);
}
countPstmt = createStatement(countQueryString);
if (parameterNames.size() != 0) {
setParameterValues(countPstmt);
}
} catch (QueryException ex) {
LOG.info("Cannot create count statement : " + ex.getMessage() + " .Will use rs.last()");
countPstmt = null;
}
}
// create statement
PreparedStatement pstmt = createStatement(queryString);
// set parameter values
if (parameterNames.size() != 0) {
setParameterValues(pstmt);
}
try {
setOutParametersValues(pstmt);
} catch (SQLException e) {
throw new QueryException(e);
} catch (DialectException e) {
throw new QueryException("Error set out parameter values for executing query : could not get dialect", e);
}
// set query's input wrapper
synchronized (inputWrapper) {
inputWrapper.statement = pstmt;
inputWrapper.countStatement = countPstmt;
inputWrapper.query = queryString;
inputWrapper.pending = true;
inputWrapper.notify();
}
synchronized (resultWrapper) {
try {
// wait for the query to complete
while (!resultWrapper.serviced) {
resultWrapper.wait();
}
if (resultWrapper.exception != null) {
throw resultWrapper.exception;
}
} catch (InterruptedException e) {
cancel();
throw e;
} finally {
resultWrapper.serviced = false;
}
if ((maxRows > 0) && (resultWrapper.count > maxRows)) {
resultWrapper.count = maxRows;
}
//must finish run method thread normally
closeRequest = true;
synchronized (inputWrapper) {
inputWrapper.pending = true;
inputWrapper.notify();
}
return new QueryResult(resultWrapper.resultSet, resultWrapper.count, resultWrapper.executeTime);
}
}
public void stop() {
closeRequest = true;
if ((inputWrapper.countStatement != null) || (inputWrapper.statement != null)) {
cancel();
}
worker.interrupt();
try {
worker.join();
} catch (InterruptedException e) {
//nothing to do
}
}
public void run() {
ResultSet resultSet = null;
SQLException sqlException = null;
int count = 0;
while (!closeRequest) {
long executeTime = 0;
synchronized(inputWrapper) {
try {
// wait for query parameters
while(!inputWrapper.pending) {
inputWrapper.wait();
}
inputWrapper.pending = false;
if (closeRequest) {
return;
}
} catch (InterruptedException e) {
if (closeRequest) {
return;
}
}
// execute query
try {
executeTime = System.currentTimeMillis();
Dialect dialect = null;
try {
dialect = DialectUtil.getDialect(conn);
} catch (DialectException e) {
e.printStackTrace();
LOG.error(e.getMessage(), e);
}
if (QueryUtil.isProcedureCall(query.getText())) {
resultSet = inputWrapper.statement.executeQuery();
if (dialect instanceof OracleDialect) {
resultSet = (ResultSet)((CallableStatement)inputWrapper.statement).getObject(outputParameterPosition);
}
// do not know how to get the number of rows
// last() and beforeFirst() do not work for an oracle stored procedure result set
// see also testForData() from ResultExporter
count = -1;
} else {
// try to get the count with a "select *"
// if that fails try to get the count with rs.last() (which is time & memory expensive)
// IMPORTANT : execute the count statement first (before the statement) ,otherwise there are
// drivers that will close the connection (Firebird), and an error of "result set is closed"
// will arise
count=-1;
boolean useLast = false;
if (inputWrapper.countStatement != null) {
ResultSet countResultSet = null;
try {
countResultSet = inputWrapper.countStatement.executeQuery();
countResultSet.next();
count = countResultSet.getInt(1);
} catch (SQLException e) {
LOG.info("Cannot execute count statement : " + e.getMessage() + " .Will use rs.last()");
useLast = true;
} finally {
ConnectionUtil.closeStatement(inputWrapper.countStatement);
ConnectionUtil.closeResultSet(countResultSet);
inputWrapper.countStatement = null;
}
} else {
if (!cancelRequest) {
useLast = true;
}
}
if (!cancelRequest) {
resultSet = inputWrapper.statement.executeQuery();
if (useLast && !cancelRequest && computeCount) {
if ((dialect instanceof SQLiteDialect) ||(dialect instanceof CSVDialect)) {
// resultSet is forward only
count = -1;
} else {
resultSet.last();
count = resultSet.getRow();
resultSet.beforeFirst();
}
}
}
}
executeTime = System.currentTimeMillis() - executeTime;
logSql(executeTime);
statementParameters.clear();
} catch (SQLException e) {
if (!cancelRequest) {
sqlException = e;
}
} catch (Throwable t) {
// catch any driver exception and log it
LOG.error(t.getMessage(), t);
if (!cancelRequest) {
sqlException = new SQLException("Execute query. See log for details") ;
}
}
}
// set query resultWrapper
synchronized (resultWrapper) {
resultWrapper.resultSet = resultSet;
resultWrapper.count = count;
resultWrapper.exception = (sqlException == null) ? null : new QueryException(sqlException);
resultWrapper.serviced = true;
resultWrapper.executeTime = executeTime;
resultWrapper.notify();
}
}
}
private void checkInputs(Query query, Map parameters,
Map parameterValues, Connection conn) throws QueryException {
if ((query == null) || (query.getText().trim().length() == 0)) {
throw new QueryException("query cannot be null");
}
if (conn == null) {
throw new QueryException("database connection cannot be null");
}
// may have hidden parameters which are not used in the query
//System.out.println("**** keys = " + ParameterUtil.getUsedParametersMap(query, parameters).keySet());
//System.out.println("++++ map="+ParameterUtil.getDebugParameters(parameterValues));
Map map = ParameterUtil.getUsedParametersMap(query, parameters);
for (String paramName : map.keySet()) {
if ((parameters == null) || (!parameters.containsKey(paramName))) {
throw new QueryException("cannot find parameter definition for " + paramName);
}
// if parameter value exists , we do not look for hidden (with default values) parameters
//
// if there is a value for that hidden parameter , it was set from another application
// (like __USER__ ) and we dont overwrite it
//
// case when parameter is not hidden and has default values interpretted dynamically is possible
// from NextReports Server from scheduler when parameter value has isDynamic = true
// (and value is not put in parameters values map)
// also if no default values are set, all parameter values will be considered (default values cannot
// contain parameters, so we need an extension to this)
if (!parameterValues.containsKey(paramName)) {
//System.out.println("**** map="+ParameterUtil.getDebugParameters(parameterValues));
//System.out.println("**** Parameter "+ paramName + " get values at runtime...");
QueryParameter param = parameters.get(paramName);
boolean hasDefaultSource = (param.getDefaultSource() != null) && !"".equals(param.getDefaultSource().trim());
boolean hasSource = (param.getSource() != null) && !"".equals(param.getSource().trim());
// we must test for default values or all values for both hidden and not hidden parameters
if (hasDefaultSource) {
try {
//System.out.println(" --> values from default source");
ParameterUtil.initDefaultParameterValues(conn, param, parameterValues);
//System.out.println("**** aftermap="+ParameterUtil.getDebugParameters(parameterValues));
} catch (QueryException ex) {
LOG.error(ex.getMessage(), ex);
throw ex;
}
} else if (hasSource) {
try {
//System.out.println(" --> all values");
ParameterUtil.initAllRuntimeParameterValues(conn, param, parameters, parameterValues);
//System.out.println("**** aftermap="+ParameterUtil.getDebugParameters(parameterValues));
} catch (QueryException ex) {
LOG.error(ex.getMessage(), ex);
throw ex;
}
} else if (param.isHidden()) {
// hidden parameter without any source, must have some default values
ParameterUtil.initDefaultParameterValues(conn, param, parameterValues);
} else {
throw new QueryException("cannot find parameter value for " + paramName);
}
}
// if (QueryUtil.isProcedureCall(query.getText())) {
// QueryParameter qp = parameters.get(paramName);
// if (QueryParameter.MULTIPLE_SELECTION.equals(qp.getSelection())) {
// throw new QueryException("Do not allow parameters with multiple selection for procedure call.");
// }
//// if (!qp.isProcedureParameter()) {
//// throw new QueryException("Parameter must be of stored procedure type.");
//// }
// }
}
}
private PreparedStatement createStatement(String queryString) throws QueryException {
// create the prepared statement
PreparedStatement pstmt;
try {
boolean hasScrollType = false;
try {
hasScrollType = DialectUtil.isSupportedResultSetType(conn, ResultSet.TYPE_SCROLL_INSENSITIVE);
} catch (Exception ex) {
ex.printStackTrace();
LOG.error(ex.getMessage(), ex);
}
int resultSetType = hasScrollType ? ResultSet.TYPE_SCROLL_INSENSITIVE : ResultSet.TYPE_FORWARD_ONLY;
if (QueryUtil.isProcedureCall(queryString)) {
pstmt = conn.prepareCall("{" + queryString + "}", resultSetType, ResultSet.CONCUR_READ_ONLY);
} else {
if (isCsv) {
pstmt = conn.prepareStatement(queryString);
} else {
boolean keepCursorsOverCommit = false;
try {
Dialect dialect = DialectUtil.getDialect(conn);
keepCursorsOverCommit = dialect.needsHoldCursorsForPreparedStatement();
} catch (DialectException e) {
e.printStackTrace();
LOG.error(e.getMessage(), e);
}
if (keepCursorsOverCommit) {
pstmt = conn.prepareStatement(queryString, resultSetType, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
} else {
pstmt = conn.prepareStatement(queryString, resultSetType, ResultSet.CONCUR_READ_ONLY);
}
}
}
// ignore queryTimeout and maxRows (some drivers - derby - not implement
// these feature yet)
try {
// set timeout
pstmt.setQueryTimeout(timeout);
// set max rows
pstmt.setMaxRows(maxRows);
} catch (SQLException e) {
LOG.warn(e);
}
} catch (SQLException e) {
throw new QueryException(e);
}
return pstmt;
}
private void setParameterValues(PreparedStatement pstmt) throws QueryException {
try {
QueryParameter parameter = null;
String parameterName = null;
Object parameterValue = null;
int n = parameterNames.size();
for (int i = 0, j = 0; (i < n) && (j < n); i++, j++) {
parameterName = parameterNames.get(j);
parameter = parameters.get(parameterName);
parameterValue = parameterValues.get(parameterName);
if (QueryParameter.MULTIPLE_SELECTION.equals(parameter.getSelection())) {
Object[] multiParamValue = (Object[]) parameterValue;
if (QueryUtil.isProcedureCall(query.getText())) {
// a multiple parameter in procedure call -> value is the list of values
int index = i;
if ((outputParameterPosition != -1) && (outputParameterPosition <= i + 1)) {
index = i + 1;
}
StringBuilder sb= new StringBuilder();
for (int k = 0; k < multiParamValue.length; k++) {
Object v = multiParamValue[k];
if (v instanceof IdName) {
v = ((IdName)v).getId();
} else if (v instanceof String) {
sb.append("'");
}
sb.append(v);
if (v instanceof String) {
sb.append("'");
}
if (k < multiParamValue.length-1) {
sb.append(",");
}
}
setParameterValue(pstmt, String.class, sb.toString(), index, true);
} else {
for (int k = 0; k < multiParamValue.length; k++) {
setParameterValue(pstmt, parameter.getValueClass(), multiParamValue[k], i);
i ++;
n ++;
}
i--;
n--;
}
} else {
int index = i;
// for procedure call if output parameter is before a query parameter
if (QueryUtil.isProcedureCall(query.getText())) {
if ((outputParameterPosition != -1) && (outputParameterPosition <= i + 1)) {
index = i + 1;
}
}
setParameterValue(pstmt, parameter.getValueClass(), parameterValue, index);
}
}
} catch (SQLException e) {
throw new QueryException("Error set parameter values for executing query", e);
}
}
private void setOutParametersValues(PreparedStatement pstmt) throws SQLException, DialectException {
Dialect dialect = DialectUtil.getDialect(conn);
if (QueryUtil.isProcedureCall(query.getText())) {
if (dialect.hasProcedureWithCursor()) {
((CallableStatement) pstmt).registerOutParameter(outputParameterPosition,dialect.getCursorSqlType());
}
}
}
private void setParameterValue(PreparedStatement pstmt, Class paramValueClass,
Object paramValue, int index) throws SQLException, QueryException {
setParameterValue(pstmt, paramValueClass, paramValue, index, false);
}
private void setParameterValue(PreparedStatement pstmt, Class paramValueClass,
Object paramValue, int index, boolean isProcedureMultiple) throws SQLException, QueryException {
// for "NOT IN (?)" setting null -> result is undeterminated
// ParameterUtil.NULL was good only for list of strings (for NOT IN)!
if (ParameterUtil.NULL.equals(paramValue)) {
paramValue = null;
}
if (isProcedureMultiple) {
// a multiple selection parameter used inside a procedure is seen as a single parameter
// with the value equals to the list of values
if (paramValue == null) {
pstmt.setNull(index + 1, Types.VARCHAR);
} else {
pstmt.setString(index + 1, (String)paramValue);
}
} else if (paramValueClass.equals(Object.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.JAVA_OBJECT);
} else {
if (paramValue instanceof IdName) {
pstmt.setObject(index + 1, ((IdName)paramValue).getId());
} else {
pstmt.setObject(index + 1, paramValue);
}
}
} else if (paramValueClass.equals(Boolean.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.BIT);
} else {
if (paramValue instanceof IdName) {
pstmt.setBoolean(index + 1, (Boolean)((IdName) paramValue).getId());
} else {
pstmt.setBoolean(index + 1, (Boolean) paramValue);
}
}
} else if (paramValueClass.equals(Byte.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.TINYINT);
} else {
if (paramValue instanceof IdName) {
pstmt.setByte(index + 1, (Byte)((IdName) paramValue).getId());
} else {
pstmt.setByte(index + 1, (Byte) paramValue);
}
}
} else if (paramValueClass.equals(Double.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.DOUBLE);
} else {
if (paramValue instanceof IdName) {
pstmt.setDouble(index + 1, (Double)((IdName) paramValue).getId());
} else {
pstmt.setDouble(index + 1, (Double) paramValue);
}
}
} else if (paramValueClass.equals(Float.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.FLOAT);
} else {
if (paramValue instanceof IdName) {
pstmt.setFloat(index + 1, (Float)((IdName) paramValue).getId());
} else {
pstmt.setFloat(index + 1, (Float) paramValue);
}
}
} else if (paramValueClass.equals(Integer.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.INTEGER);
} else {
if (paramValue instanceof IdName) {
pstmt.setObject(index + 1, ((IdName) paramValue).getId());
} else {
pstmt.setInt(index + 1, (Integer) paramValue);
}
}
} else if (paramValueClass.equals(Long.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.BIGINT);
} else {
if (paramValue instanceof IdName) {
pstmt.setLong(index + 1, (Long)((IdName) paramValue).getId());
} else {
pstmt.setLong(index + 1, (Long) paramValue);
}
}
} else if (paramValueClass.equals(Short.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.SMALLINT);
} else {
if (paramValue instanceof IdName) {
pstmt.setShort(index + 1, (Short)((IdName) paramValue).getId());
} else {
pstmt.setShort(index + 1, (Short) paramValue);
}
}
//@todo
// ParameterUtil -> values are taken from dialect (where there is no BigDecimal yet!)
// or from meta data
} else if (paramValueClass.equals(BigDecimal.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.DECIMAL);
} else {
if (paramValue instanceof IdName) {
Serializable ser = ((IdName) paramValue).getId();
if (ser instanceof BigDecimal) {
pstmt.setBigDecimal(index + 1, (BigDecimal)(ser));
} else {
pstmt.setInt(index + 1, (Integer)(ser));
}
} else {
// a simple value cannot be cast to BigDecimal!
pstmt.setObject(index + 1, paramValue);
}
}
} else if (paramValueClass.equals(BigInteger.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.BIGINT);
} else {
if (paramValue instanceof IdName) {
Serializable ser = ((IdName) paramValue).getId();
if (ser instanceof BigInteger) {
pstmt.setBigDecimal(index + 1, new BigDecimal((BigInteger)(ser)));
} else if (ser instanceof BigDecimal) {
pstmt.setBigDecimal(index + 1, (BigDecimal)(ser));
} else {
pstmt.setInt(index + 1, (Integer)(ser));
}
} else {
// a simple value cannot be cast to BigDecimal!
pstmt.setObject(index + 1, paramValue);
}
}
} else if (paramValueClass.equals(String.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.VARCHAR);
} else {
if (paramValue instanceof IdName) {
if (((IdName)paramValue).getId() == null) {
pstmt.setNull(index + 1,Types.VARCHAR);
} else {
pstmt.setString(index + 1, ((IdName)paramValue).getId().toString());
}
} else {
pstmt.setString(index + 1, paramValue.toString());
}
}
} else if (paramValueClass.equals(Date.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.DATE);
} else {
if (paramValue instanceof IdName) {
Serializable obj = ((IdName)paramValue).getId();
Date date;
if (obj instanceof String) {
try {
date = IdNameRenderer.sdf.parse((String)obj);
} catch (ParseException e) {
e.printStackTrace();
LOG.error(e.getMessage(), e);
date = new Date();
}
} else {
date = (Date)obj;
}
pstmt.setDate(index + 1, new java.sql.Date(date.getTime()));
} else {
pstmt.setDate(index + 1, new java.sql.Date(((Date) paramValue).getTime()));
}
}
} else if (paramValueClass.equals(Timestamp.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.TIMESTAMP);
} else {
if (paramValue instanceof IdName) {
Serializable obj = ((IdName)paramValue).getId();
Date date;
if (obj instanceof String) {
try {
date = IdNameRenderer.sdf.parse((String)obj);
} catch (ParseException e) {
e.printStackTrace();
LOG.error(e.getMessage(), e);
date = new Date();
}
} else {
date = (Date)obj;
}
pstmt.setTimestamp(index + 1, new Timestamp(date.getTime()));
} else {
pstmt.setTimestamp(index + 1, new Timestamp(((Date) paramValue).getTime()));
}
}
} else if (paramValueClass.equals(Time.class)) {
if (paramValue == null) {
pstmt.setNull(index + 1, Types.TIME);
} else {
if (paramValue instanceof IdName) {
Serializable obj = ((IdName)paramValue).getId();
Date date;
if (obj instanceof String) {
try {
date = IdNameRenderer.sdf.parse((String)obj);
} catch (ParseException e) {
e.printStackTrace();
LOG.error(e.getMessage(), e);
date = new Date();
}
} else {
date = (Date)obj;
}
pstmt.setTime(index + 1, new Time( date.getTime()));
} else {
pstmt.setTime(index + 1, new Time (((Date) paramValue).getTime()));
}
}
} else {
throw new QueryException("Parameter type " + paramValueClass.getName() +
" not supported in query");
}
// for logSql()
statementParameters.put(index, paramValue);
}
/**
* Parse query and return a string query that will be passed to prepared
* statement(substitute parameter with '?' char).
*/
private String createQueryString() {
QueryChunk[] chunks = query.getChunks();
if ((chunks == null) || (chunks.length == 0)) {
// no query chunks
return "";
}
StringBuffer sb = new StringBuffer();
QueryChunk chunk = null;
int position = 1;
for (int i = 0; i < chunks.length; i++) {
chunk = chunks[i];
//System.out.println("chunk = " + chunk);
switch (chunk.getType()) {
case QueryChunk.PARAMETER_TYPE: {
position++;
String paramName = chunk.getText();
QueryParameter param = parameters.get(paramName);
if (QueryParameter.MULTIPLE_SELECTION.equals(param.getSelection())) {
if (QueryUtil.isProcedureCall(query.getText())) {
sb.append("?");
} else {
Object[] paramValue = (Object[]) parameterValues.get(paramName);
sb.append('(');
for (int j = 0; j < paramValue.length; j++) {
if (j > 0) {
sb.append(',');
}
sb.append('?');
}
sb.append(')');
}
} else {
sb.append("?");
}
break;
}
case QueryChunk.TEXT_TYPE:
if (chunk.getText().contains("?")) {
outputParameterPosition = position;
}
default: {
sb.append(chunk.getText());
break;
}
}
}
return sb.toString();
}
private void cancel() {
cancelRequest = true;
try {
if (inputWrapper.countStatement != null) {
inputWrapper.countStatement.cancel();
}
inputWrapper.statement.cancel();
synchronized(resultWrapper) {
while(!resultWrapper.serviced) {
resultWrapper.wait();
}
}
} catch (SQLException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
cancelRequest = false;
}
}
private void processIgnoreParameters(Query query, Map parameters,
Map parameterValues) {
List ignoredList = new ArrayList();
if (parameters == null) {
return;
}
for (Iterator it = parameters.keySet().iterator(); it.hasNext();) {
String name = (String)it.next();
QueryParameter param = parameters.get(name);
if (param.isIgnore()) {
ignoredList.add("${" + name + "}");
it.remove();
parameterValues.remove(name);
}
}
//System.out.println("----------- processIgnoreParameters");
//System.out.println("parameters ignoredList = " + ignoredList);
if (ignoredList.size() == 0) {
return;
}
String sql = StringUtil.deleteExcededSpaces(query.getText());
//System.out.println("sql = " + sql);
// removed indexex
Set indexes = new HashSet();
Set columns = new HashSet();
// split using any space characters
String[] words = sql.split("\\s");
for (int i=0, size=words.length; i i="+i + " word=" + words[i] + " pIndex="+pIndex);
if (pIndex != -1) {
indexes.add(i);
indexes.add(i-1);
indexes.add(i-2);
columns.add(i-2);
//System.out.println("Find parameter " + words[i]);
if (words[i-1].equalsIgnoreCase(IN) || words[i-1].equalsIgnoreCase(LIKE)) {
// check for NOT
if (words[i-2].equalsIgnoreCase(NOT)) {
indexes.add(i-3);
}
} else if (words[i-1].equalsIgnoreCase(AND)) {
// BETWEEN
indexes.add(i-3);
indexes.add(i-4);
// only one 1=1 must be added for a between
columns.remove(i-2);
} else if (words[i-1].equalsIgnoreCase(BETWEEN)) {
// AND
indexes.add(i+1);
indexes.add(i+2);
}
}
}
StringBuilder newSql = new StringBuilder();
for (int i=0, size=words.length; i list) {
for (int i=0, size=list.size(); i (" + time + " ms)");
}
}
class InputWrapper {
public PreparedStatement statement;
public PreparedStatement countStatement;
public String query;
public boolean pending;
}
class ResultWrapper {
public ResultSet resultSet;
public QueryException exception;
public int count;
public boolean serviced;
public long executeTime;
}
private String getCsvCountQuery(String query) {
if (query == null) {
return null;
}
query = query.toLowerCase();
int index = query.indexOf("from");
if (index == -1) {
return null;
}
return "select count(*) from " + query.substring(index + 4);
}
}