{
//try to find an expression
expr = compileExpression();
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("')' expected", p.getIndex(), p.getInput());
}
expr.encloseWithInParentheses();
}
else if (p.parseChar('{'))
{
//try to find an array
List exprs = new ArrayList();
while (!p.parseChar('}'))
{
exprs.add(compileExpression());
if (p.parseChar('}'))
{
break;
}
else if (!p.parseChar(','))
{
throw new QueryCompilerSyntaxException("',' or '}' expected", p.getIndex(), p.getInput());
}
}
expr = new ArrayExpression(qs, (ScalarExpression[])exprs.toArray(new ScalarExpression[exprs.size()]));
}
else if (p.parseStringIgnoreCase("EXISTS"))
{
expr = compileIdentifier();
if (expr instanceof SubqueryExpression)
{
((SubqueryExpression)expr).exists();
}
else
{
throw new JPOXUserException("EXISTS can only be followed by a subquery expression");
}
}
else if (p.parseStringIgnoreCase("ALL"))
{
expr = compileIdentifier();
if (expr instanceof SubqueryExpression)
{
((SubqueryExpression)expr).all();
}
else
{
throw new JPOXUserException("ALL can only be followed by a subquery expression");
}
}
else if (p.parseStringIgnoreCase("ANY"))
{
expr = compileIdentifier();
if (expr instanceof SubqueryExpression)
{
((SubqueryExpression)expr).any();
}
else
{
throw new JPOXUserException("ANY can only be followed by a subquery expression");
}
}
else if (p.parseStringIgnoreCase("SOME"))
{
expr = compileIdentifier();
if (expr instanceof SubqueryExpression)
{
((SubqueryExpression)expr).any(); // SOME same as ANY
}
else
{
throw new JPOXUserException("SOME can only be followed by a subquery expression");
}
}
else
{
String methodId = p.parseMethod();
if (methodId == null)
{
// We will have an identifier (can be an variable, parameter or a field in the candidate class)
expr = compileIdentifier();
}
else
{
// we are running arbitrary methods. the namespace here is "<candidateAlias>"
if (p.parseChar('('))
{
if (methodId.equals("TRIM"))
{
// "TRIM([[LEADING|TRAILING|BOTH] [posn] FROM] string_primary)"
boolean leading = true;
boolean trailing = true;
if (p.parseStringIgnoreCase("LEADING"))
{
trailing = false;
}
else if (p.parseStringIgnoreCase("TRAILING"))
{
leading = false;
}
else if (p.parseStringIgnoreCase("BOTH"))
{
// Default
}
// TODO Support trimChar
p.parseStringIgnoreCase("FROM"); // Ignore FROM keyword
ScalarExpression argExpr = compileExpression(); // The field/literal to trim
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("')' expected", p.getIndex(), p.getInput());
}
if (leading && trailing)
{
return argExpr.callMethod("trim", Collections.EMPTY_LIST);
}
else if (leading)
{
return argExpr.callMethod("trimLeft", Collections.EMPTY_LIST);
}
else
{
return argExpr.callMethod("trimRight", Collections.EMPTY_LIST);
}
}
else
{
// JPQL Function expression
List args = new ArrayList();
boolean isDistinct = false;
if (!p.parseChar(')'))
{
// Check for use of DISTINCT (case insensitive)
isDistinct = p.parseStringIgnoreCase("DISTINCT");
do
{
ScalarExpression argExpr = compileExpression();
args.add(argExpr);
fieldExpressions.remove(argExpr); // Remove from field expressions list since we will include aggregates
} while (p.parseChar(','));
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("')' expected", p.getIndex(), p.getInput());
}
}
MappedStoreManager srm =
(MappedStoreManager)(qs != null ? qs.getStoreManager() : query.getObjectManager().getStoreManager());
//TODO make these functions pluggable
if (methodId.equalsIgnoreCase("ABS"))
{
return new MathExpression(qs).absMethod(((ScalarExpression) args.get(0)));
}
else if (methodId.equalsIgnoreCase("SQRT"))
{
return new MathExpression(qs).sqrtMethod(((ScalarExpression) args.get(0)));
}
else if (methodId.equalsIgnoreCase("CONCAT"))
{
return ((ScalarExpression) args.get(0)).add((ScalarExpression) args.get(1));
}
else if (methodId.equalsIgnoreCase("MOD"))
{
return ((ScalarExpression) args.get(0)).mod((ScalarExpression) args.get(1));
}
else if (methodId.equalsIgnoreCase("LENGTH"))
{
return ((ScalarExpression) args.get(0)).callMethod(methodId.toLowerCase(),
Collections.EMPTY_LIST);
}
else if (methodId.equalsIgnoreCase("SUBSTRING"))
{
List argscall = new ArrayList();
JavaTypeMapping mapping = srm.getDatastoreAdapter().getMapping(String.class, srm);
IntegerLiteral one = new IntegerLiteral(qs, mapping, BigInteger.ONE, false);
argscall.add(((ScalarExpression) args.get(1)).sub(one));
if (args.size() > 2)
{
argscall.add(((ScalarExpression) args.get(2)).add(one));
}
return ((ScalarExpression) args.get(0)).callMethod(methodId.toLowerCase(), argscall);
}
else if (methodId.equalsIgnoreCase("LOWER"))
{
return ((ScalarExpression) args.get(0)).callMethod("toLowerCase",
Collections.EMPTY_LIST);
}
else if (methodId.equalsIgnoreCase("UPPER"))
{
return ((ScalarExpression) args.get(0)).callMethod("toUpperCase",
Collections.EMPTY_LIST);
}
else if (methodId.equalsIgnoreCase("SIZE"))
{
return ((ScalarExpression) args.get(0)).callMethod(methodId.toLowerCase(),
Collections.EMPTY_LIST);
}
else if (methodId.equalsIgnoreCase("LOCATE"))
{
List argscall = new ArrayList();
argscall.add(args.get(0));
JavaTypeMapping mapping = srm.getDatastoreAdapter().getMapping(String.class, srm);
IntegerLiteral one = new IntegerLiteral(qs, mapping, BigInteger.ONE,false);
if (args.size() > 2)
{
argscall.add(((ScalarExpression)args.get(2)).sub(one));
}
return ((ScalarExpression)args.get(1)).callMethod("indexOf", argscall).add(one);
}
else
{
expr = new AggregateExpression(qs);
if (isDistinct)
{
((AggregateExpression) expr).setDistinct();
}
// Allow for aggregate functions specified in lowercase/UPPERCASE
try
{
expr = expr.callMethod(methodId.toLowerCase(), args);
fieldExpressions.add(expr); // Remove from field exprs since we dont include aggregates
}
catch (MethodInvocationException ex)
{
if (methodId.equalsIgnoreCase("Object"))
{
// Object(p)
expr = (ScalarExpression) args.get(0);
}
}
}
}
}
}
}
}
/*
* run function on literals or identifiers
* e.g. "primary.runMethod(arg)"
*/
while (p.parseChar('.'))
{
String id = p.parseIdentifier();
if (id == null)
{
throw new QueryCompilerSyntaxException("Identifier expected", p.getIndex(), p.getInput());
}
if (p.parseChar('('))
{
// Found syntax for a method, so invoke the method
ArrayList args = new ArrayList();
if (!p.parseChar(')'))
{
do
{
args.add(compileExpression());
} while (p.parseChar(','));
if (!p.parseChar(')'))
{
throw new QueryCompilerSyntaxException("')' expected", p.getIndex(), p.getInput());
}
}
expr = expr.callMethod(id, args);
}