public Object visit(RelationQueryNode node, Object data) throws RepositoryException {
PathQueryNode relPath = node.getRelativePath();
if (relPath == null
&& node.getOperation() != QueryConstants.OPERATION_SIMILAR
&& node.getOperation() != QueryConstants.OPERATION_SPELLCHECK) {
exceptions.add(new InvalidQueryException("@* not supported in predicate"));
return data;
}
LocationStepQueryNode[] steps = relPath.getPathSteps();
Name propertyName = steps[steps.length - 1].getNameTest();
Query query;
String[] stringValues = new String[1];
switch (node.getValueType()) {
case 0:
// not set: either IS NULL or IS NOT NULL
break;
case QueryConstants.TYPE_DATE:
stringValues[0] = DateField.dateToString(node.getDateValue());
break;
case QueryConstants.TYPE_DOUBLE:
stringValues[0] = DoubleField.doubleToString(node.getDoubleValue());
break;
case QueryConstants.TYPE_LONG:
stringValues[0] = LongField.longToString(node.getLongValue());
break;
case QueryConstants.TYPE_STRING:
if (node.getOperation() == QueryConstants.OPERATION_EQ_GENERAL
|| node.getOperation() == QueryConstants.OPERATION_EQ_VALUE
|| node.getOperation() == QueryConstants.OPERATION_NE_GENERAL
|| node.getOperation() == QueryConstants.OPERATION_NE_VALUE) {
// only use coercing on non-range operations
stringValues = getStringValues(propertyName, node.getStringValue());
} else {
stringValues[0] = node.getStringValue();
}
break;
case QueryConstants.TYPE_POSITION:
// ignore position. is handled in the location step
return null;
default:
throw new IllegalArgumentException("Unknown relation type: "
+ node.getValueType());
}
// get property transformation
final int[] transform = new int[]{TransformConstants.TRANSFORM_NONE};
node.acceptOperands(new DefaultQueryNodeVisitor() {
public Object visit(PropertyFunctionQueryNode node, Object data) {
if (node.getFunctionName().equals(PropertyFunctionQueryNode.LOWER_CASE)) {
transform[0] = TransformConstants.TRANSFORM_LOWER_CASE;
} else if (node.getFunctionName().equals(PropertyFunctionQueryNode.UPPER_CASE)) {
transform[0] = TransformConstants.TRANSFORM_UPPER_CASE;
}
return data;
}
}, null);
if (node.getOperation() == QueryConstants.OPERATION_SIMILAR) {
// this is a bit ugly:
// use the name of a dummy property because relPath actually
// references a property. whereas the relPath of the similar
// operation references a node
propertyName = NameConstants.JCR_PRIMARYTYPE;
}
String field = "";
try {
field = resolver.getJCRName(propertyName);
} catch (NamespaceException e) {
// should never happen
exceptions.add(e);
}
// support for fn:name()
if (propertyName.getNamespaceURI().equals(SearchManager.NS_FN_URI)
&& propertyName.getLocalName().equals("name()")) {
if (node.getValueType() != QueryConstants.TYPE_STRING) {
exceptions.add(new InvalidQueryException("Name function can "
+ "only be used in conjunction with a string literal"));
return data;
}
if (node.getOperation() != QueryConstants.OPERATION_EQ_VALUE
&& node.getOperation() != QueryConstants.OPERATION_EQ_GENERAL) {
exceptions.add(new InvalidQueryException("Name function can "
+ "only be used in conjunction with an equals operator"));
return data;
}
// check if string literal is a valid XML Name
if (XMLChar.isValidName(node.getStringValue())) {