in source/com.microsoft.tfs.core/src/com/microsoft/tfs/core/clients/workitem/internal/wiqlparse/WIQLAdapter.java [647:848]
public Node optimizeNode(Node node, final NodeTableName tableContext, final NodeFieldName fieldContext) {
if (node.getNodeType() == NodeType.FIELD_CONDITION) {
final NodeCondition nodeCondition = (NodeCondition) node;
// convert (A in B) block to the multiple blocks
if (nodeCondition.getCondition() == Condition.IN) {
// create new Or node
final NodeOrOperator nodeOr = new NodeOrOperator();
final NodeValueList valueList = (NodeValueList) nodeCondition.getRight();
// process all values inside value list
for (final Iterator<Node> it = valueList.iterator(); it.hasNext();) {
final Node valueItem = it.next();
nodeOr.add(new NodeCondition(Condition.EQUALS, nodeCondition.getLeft(), valueItem));
}
// optimize new "Or" group
return nodeOr.optimize(this, tableContext, fieldContext);
} else if (nodeCondition.getCondition() == Condition.CONTAINS
|| nodeCondition.getCondition() == Condition.CONTAINS_WORDS) {
// optimize contains
final String s = nodeCondition.getRight().getConstStringValue();
if (s != null && s.length() == 0) {
// empty pattern - always true
return new NodeBoolConst(true);
}
}
// field usage is a tag of the left part
final NodeFieldName field = nodeCondition.getLeft();
final FieldDefinitionImpl fd = (FieldDefinitionImpl) field.getTag();
// convert Project-field condition to Area Path conditions
if (fd.getID() == CoreFields.TEAM_PROJECT) {
final String pathValue = nodeCondition.getRight().getConstStringValue();
if (pathValue != null) {
final FieldDefinitionImpl pathField =
witContext.getFieldDefinitions().getFieldDefinitionInternal(CoreFields.AREA_PATH);
// construct new condition
node = new NodeCondition(
Condition.UNDER,
new NodeFieldName(field.getPrefix(), pathField.getName()),
new NodeString(pathValue));
if (nodeCondition.getCondition() == Condition.NOT_EQUALS) {
node = new NodeNotOperator(node);
}
// Bind new operator
node.bind(this, tableContext, fieldContext);
}
}
if (isNonNullableField(fd.getID())) {
// optimize contains
final String s = nodeCondition.getRight().getConstStringValue();
if (s != null && s.length() == 0) {
if (nodeCondition.getCondition() == Condition.NOT_EQUALS) {
// it always not empty
return new NodeBoolConst(true);
}
}
}
if (dayPrecision && (field.getDataType() == DataType.DATE)) {
// check time part of a constant -- must be 0
final String rightString = nodeCondition.getRight().getConstStringValue();
if (rightString != null && rightString.length() != 0) {
Date d = DateTime.parse(rightString, getLocale(), getTimeZone());
final Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(getTimeZone());
calendar.setTime(d);
final boolean nonZeroTime = (calendar.get(Calendar.HOUR_OF_DAY) != 0)
|| (calendar.get(Calendar.MINUTE) != 0)
|| (calendar.get(Calendar.SECOND) != 0)
|| (calendar.get(Calendar.MILLISECOND) != 0);
Tools.ensureSyntax(!nonZeroTime, SyntaxError.NON_ZERO_TIME, node);
// Create constants for start and end of period
final NodeString startDay = new NodeString(DateTime.formatRoundTripLocal(d, getTimeZone()));
// TODO: Handle d == 31/12/9999 case (VS Bug 613231)
// Add a day
final Calendar c = Calendar.getInstance();
c.setTime(d);
c.setTimeZone(getTimeZone());
c.add(Calendar.DAY_OF_MONTH, 1);
d = c.getTime();
final NodeString nextDay = new NodeString(DateTime.formatRoundTripLocal(d, getTimeZone()));
if (nodeCondition.getCondition() == Condition.EQUALS) {
// Convert to a pair of conditions
final NodeAndOperator nodeAnd = new NodeAndOperator();
nodeAnd.add(new NodeCondition(Condition.GREATER_OR_EQUALS, nodeCondition.getLeft(), startDay));
nodeAnd.add(new NodeCondition(Condition.LESS, nodeCondition.getLeft(), nextDay));
node = nodeAnd;
node.bind(this, tableContext, fieldContext);
} else if (nodeCondition.getCondition() == Condition.NOT_EQUALS) {
final NodeOrOperator nodeOr = new NodeOrOperator();
nodeOr.add(new NodeCondition(Condition.LESS, nodeCondition.getLeft(), startDay));
nodeOr.add(new NodeCondition(Condition.GREATER_OR_EQUALS, nodeCondition.getLeft(), nextDay));
node = nodeOr;
node.bind(this, tableContext, fieldContext);
} else if (nodeCondition.getCondition() == Condition.LESS
|| nodeCondition.getCondition() == Condition.GREATER_OR_EQUALS) {
nodeCondition.setRight(startDay);
} else if (nodeCondition.getCondition() == Condition.GREATER) {
nodeCondition.setCondition(Condition.GREATER_OR_EQUALS);
nodeCondition.setRight(nextDay);
} else if (nodeCondition.getCondition() == Condition.LESS_OR_EQUALS) {
nodeCondition.setCondition(Condition.LESS);
nodeCondition.setRight(nextDay);
} else {
Tools.ensureSyntax(false, SyntaxError.INVALID_CONDITIONAL_OPERATOR, node);
}
}
}
} else if (node.getNodeType() == NodeType.VARIABLE) {
final NodeVariable nodeVariable = (NodeVariable) node;
if (context != null) {
final Object o = context.get(nodeVariable.getTag());
if (o != null) {
if ((o instanceof Integer) || (o instanceof Double)) {
return new NodeNumber(o.toString());
}
return new NodeString(o.toString());
}
}
if (ME.equals(nodeVariable.getTag())) {
// replace "me" with user name
return new NodeString(witContext.getCurrentUserDisplayName());
}
if (TODAY.equals(nodeVariable.getTag())) {
final Date today = DateTime.today(getTimeZone());
return new NodeString(DateTime.formatRoundTripLocal(today, getTimeZone()));
}
} else if (node.getNodeType() == NodeType.ARITHMETIC) {
final NodeArithmetic a = (NodeArithmetic) node;
final NodeNumber right = (NodeNumber) a.getRight();
if (fieldContext == null || fieldContext.getDataType() == DataType.NUMERIC) {
final NodeNumber left = (NodeNumber) a.getLeft();
double d = Double.parseDouble(left.getValue());
final double inc = Double.parseDouble(right.getValue());
if (a.getArithmetic() == Arithmetic.ADD) {
d += inc;
} else if (a.getArithmetic() == Arithmetic.SUBTRACT) {
d -= inc;
} else {
throw new RuntimeException();
}
return new NodeNumber(String.valueOf(d));
}
if (fieldContext != null && fieldContext.getDataType() == DataType.DATE) {
final NodeString left = (NodeString) a.getLeft();
Date d = DateTime.parse(left.getValue(), getLocale(), getTimeZone());
boolean isIntegerDays = false;
int integerDays = -1;
try {
integerDays = Integer.parseInt(right.getValue());
isIntegerDays = true;
} catch (final NumberFormatException ex) {
}
if (isIntegerDays) {
final Calendar calendar = Calendar.getInstance();
calendar.setTime(d);
calendar.setTimeZone(getTimeZone());
if (a.getArithmetic() == Arithmetic.ADD) {
calendar.add(Calendar.DAY_OF_MONTH, integerDays);
} else if (a.getArithmetic() == Arithmetic.SUBTRACT) {
calendar.add(Calendar.DAY_OF_MONTH, -1 * integerDays);
} else {
throw new UnsupportedOperationException();
}
d = calendar.getTime();
} else {
final double doubleDays = Double.parseDouble(right.getValue());
final long millis = (long) ((doubleDays * (60 * 60 * 24 * 1000)) + 0.5);
if (a.getArithmetic() == Arithmetic.ADD) {
d = new Date(d.getTime() + millis);
} else if (a.getArithmetic() == Arithmetic.SUBTRACT) {
d = new Date(d.getTime() - millis);
} else {
throw new UnsupportedOperationException();
}
}
return new NodeString(DateTime.formatRoundTripLocal(d, getTimeZone()));
}
}
return node;
}