package edu.harvard.i2b2.crc.util;
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.harvard.i2b2.common.exception.I2B2Exception;
import edu.harvard.i2b2.common.util.db.JDBCUtil;
/**
* Class to build sql clause from the input, to catch sql injection attack.
*
*
*/
public class SqlClauseUtil {
protected final static Log log = LogFactory.getLog(SqlClauseUtil.class);
public final static String REGEXP_IN_CLAUSE = ",(?!(?:[^',]|[^'],[^'])+')";
/**
* Rebuild the sql IN clause from the input value constrain
*
* @param theValueCons
* @param encloseSingleQuote
* @return
*/
public static String buildINClause(String theValueCons,
boolean encloseSingleQuote) {
// add '' for each inValues
int i = 0;
String singleInValue = "", inConstrainValue = "", singleQuote = "";
if (encloseSingleQuote) {
singleQuote = "'";
}
theValueCons = theValueCons.trim();
if (theValueCons.startsWith("(")) {
theValueCons = theValueCons.substring(1, theValueCons.length() - 1);
}
String[] inValues = null;
if (encloseSingleQuote) {
inValues = theValueCons.split(REGEXP_IN_CLAUSE);
} else {
inValues = theValueCons.split(",");
}
while (i < inValues.length) {
if (encloseSingleQuote) {
singleInValue = inValues[i].substring(1,
inValues[i].length() - 1);
} else {
singleInValue = inValues[i];
}
inConstrainValue += singleQuote
+ singleInValue.replaceAll("'", "''") + singleQuote;
if (i + 1 < inValues.length) {
inConstrainValue += ",";
}
i++;
log.debug("Rebuilding the IN Clause with regex ["
+ REGEXP_IN_CLAUSE + "], element value [" + singleInValue
+ "] and the built value [" + inConstrainValue + "]");
}
return inConstrainValue;
}
/**
* Rebuild the sql BETWEEN clause from the input value constrain
*
* @param betweenConstraint
* @return
* @throws I2B2Exception
*/
public static String buildBetweenClause(String betweenConstraint)
throws I2B2Exception {
StringTokenizer st = new StringTokenizer(betweenConstraint);
String firstElement = "", andElement = "", thirdElement = "";
if (st.countTokens() == 3) {
firstElement = st.nextToken();
andElement = st.nextToken();
thirdElement = st.nextToken();
if (!andElement.equalsIgnoreCase("and")) {
throw new I2B2Exception("Invalid between clause ["
+ betweenConstraint + "]");
}
} else {
throw new I2B2Exception("Invalid between clause ["
+ betweenConstraint + "]");
}
return firstElement.replaceAll("'", "''") + " and "
+ thirdElement.replaceAll("'", "''");
}
public static boolean isEnclosedinSingleQuote(String value) {
if (value.startsWith("'") && value.endsWith("'")) {
return true;
} else {
return false;
}
}
public static boolean isEnclosedinBraces(String value) {
if (value.startsWith("(") && value.endsWith(")")) {
return true;
} else {
return false;
}
}
public static String handleMetaDataTextValue(String operator,String value) {
String formattedValue = value;
if ((operator != null)
&& (operator.toUpperCase().equals("LIKE"))) {
boolean needPercentFlag = false, needSlashFlag = false;
//if not enclosed in single quote
if (!SqlClauseUtil.isEnclosedinSingleQuote(formattedValue)) {
//escape the single quote
formattedValue = JDBCUtil.escapeSingleQuote(formattedValue);
// if missing \
if (formattedValue.lastIndexOf('%') != formattedValue.length() - 1) {
needPercentFlag = true;
}
//else if missing %
if (needPercentFlag) {
if (formattedValue.lastIndexOf('\\') != formattedValue.length() - 1) {
log.debug("Adding \\ at the end of the Concept path ");
needSlashFlag = true;
}
} else {
if (formattedValue.lastIndexOf('\\') != formattedValue.length() - 2) {
log.debug("Adding \\ at the end of the Concept path ");
needSlashFlag = true;
}
}
if (needSlashFlag) {
if (needPercentFlag) {
formattedValue=formattedValue+"\\%";
} else {
formattedValue = formattedValue + "\\";
}
} else if (needPercentFlag) {
formattedValue = formattedValue + "%";
}
formattedValue = "'" + formattedValue + "'";
}
} else if (operator.toUpperCase().equals("IN")) {
formattedValue = value;
formattedValue = SqlClauseUtil.buildINClause(formattedValue, true);
formattedValue = "(" + formattedValue + ")";
} else {
boolean needSingleQuoteFlag = false;
formattedValue = value;
//escape the single quote
formattedValue = JDBCUtil.escapeSingleQuote(formattedValue);
// if not enclosed in '', add it
if (!SqlClauseUtil.isEnclosedinSingleQuote(value)) {
needSingleQuoteFlag = true;
}
if (needSingleQuoteFlag) {
formattedValue = "'" + formattedValue + "'";
}
}
return formattedValue;
}
public static String handleMetaDataNumericValue(String operator, String value) {
String formattedValue = "";
boolean needBracesFlag = false;
//if operator is IN, then add open and close braces if it is missing
if (operator.toUpperCase().equals("IN")) {
if (!SqlClauseUtil.isEnclosedinBraces(value)) {
needBracesFlag = true;
}
}
if (needBracesFlag) {
formattedValue = "(" + value + ")";
} else {
formattedValue = value;
}
return formattedValue;
}
public static String handleMetaDataDateValue(String operator, String value) {
String formattedValue = "";
boolean needBracesFlag = false;
//if operator is IN, then add open and close braces if it is missing
if (operator.toUpperCase().equals("IN")) {
if (!SqlClauseUtil.isEnclosedinBraces(value)) {
needBracesFlag = true;
}
}
if (needBracesFlag) {
formattedValue = "(" + value + ")";
} else {
formattedValue = value;
}
return formattedValue;
}
}