/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2009 Jaspersoft Corporation. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.jasperreports.engine.query;
import java.lang.reflect.Array;
import java.util.Collection;
import net.sf.jasperreports.engine.JRRuntimeException;
/**
* Base (NOT) IN clause function for SQL queries.
*
* @author Lucian Chirita (lucianc@users.sourceforge.net)
* @version $Id: JRSqlAbstractInClause.java 3222 2009-11-30 10:34:21Z lucianc $
*/
public abstract class JRSqlAbstractInClause implements JRClauseFunction
{
protected static final int POSITION_DB_COLUMN = 1;
protected static final int POSITION_PARAMETER = 2;
protected static final String CLAUSE_TRUISM = "0 = 0";
protected JRSqlAbstractInClause()
{
}
/**
* Creates a (NOT) IN SQL clause.
*
* <p>
* The function expects two clause tokens (after the ID token):
* <ul>
* <li>The first token is the SQL column to be used in the clause.</li>
* <li>The second token is the name of the report parameter that contains the value list.
* <br/>
* The value of this parameter has to be an array, a <code>java.util.Collection</code>
* or <code>null</code>.
* </li>
* </p>
*
* <p>
* The function constructs a <code>column [NOT] IN (?, ?, .., ?)</code> clause.
* If the values list is null or empty, the function generates a SQL clause that
* will always evaluate to true (e.g. <code>0 = 0</code>).
* </p>
*/
public void apply(JRClauseTokens clauseTokens, JRQueryClauseContext queryContext)
{
String col = clauseTokens.getToken(POSITION_DB_COLUMN);
String param = clauseTokens.getToken(POSITION_PARAMETER);
if (col == null)
{
throw new JRRuntimeException("SQL IN clause missing DB column token");
}
if (param == null)
{
throw new JRRuntimeException("SQL IN clause missing parameter token");
}
StringBuffer sbuffer = queryContext.queryBuffer();
Object paramValue = queryContext.getValueParameter(param).getValue();
if (paramValue == null)
{
handleNoValues(queryContext);
}
else
{
int count = valuesCount(param, paramValue);
if (count == 0)
{
handleNoValues(queryContext);
}
else
{
sbuffer.append(col);
sbuffer.append(' ');
appendInOperator(sbuffer);
sbuffer.append(' ');
sbuffer.append('(');
for (int idx = 0; idx < count; ++idx)
{
if (idx > 0)
{
sbuffer.append(", ");
}
sbuffer.append('?');
}
sbuffer.append(')');
queryContext.addQueryMultiParameters(param, count);
}
}
}
protected void handleNoValues(JRQueryClauseContext queryContext)
{
queryContext.queryBuffer().append(CLAUSE_TRUISM);
}
protected int valuesCount(String paramName, Object paramValue)
{
int count;
if (paramValue.getClass().isArray())
{
count = Array.getLength(paramValue);
}
else if (paramValue instanceof Collection)
{
count = ((Collection) paramValue).size();
}
else
{
throw new JRRuntimeException("Invalid type " + paramValue.getClass().getName() +
" for parameter " + paramName + " used in an IN clause; the value must be an array or a collection.");
}
return count;
}
protected abstract void appendInOperator(StringBuffer sBuffer);
}