Builder for JPQL expressions. This class takes the query parsed
in
. Public for unit testing purposes.
| Method from org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder Detail: |
protected String currentQuery() {
return ctx().parsed == null || root().parser == null ? null
: root().parser.jpql;
}
|
protected Expression evalFetchJoins(QueryExpressions exps) {
Expression filter = null;
// handle JOIN FETCH
Set joins = null;
Set innerJoins = null;
JPQLNode[] outers = root().findChildrenByID(JJTOUTERFETCHJOIN);
for (int i = 0; outers != null && i < outers.length; i++)
(joins == null ? joins = new TreeSet() : joins).
add(getPath(onlyChild(outers[i])).last().getFullName(false));
JPQLNode[] inners = root().findChildrenByID(JJTINNERFETCHJOIN);
for (int i = 0; inners != null && i < inners.length; i++) {
String path = getPath(onlyChild(inners[i])).last()
.getFullName(false);
(joins == null ? joins = new TreeSet() : joins).add(path);
(innerJoins == null ? innerJoins = new TreeSet() : innerJoins).
add(path);
}
if (joins != null)
exps.fetchPaths = (String[]) joins.
toArray(new String[joins.size()]);
if (innerJoins != null)
exps.fetchInnerPaths = (String[]) innerJoins.
toArray(new String[innerJoins.size()]);
return filter;
}
|
protected void evalSetClause(QueryExpressions exps) {
// handle SET field = value
JPQLNode[] nodes = root().findChildrenByID(JJTUPDATEITEM);
for (int i = 0; nodes != null && i < nodes.length; i++) {
Path path = getPath(firstChild(nodes[i]));
Value val = getValue(onlyChild(lastChild(nodes[i])));
exps.putUpdate(path, val);
}
}
|
protected ClassMetaData getCandidateMetaData(JPQLExpressionBuilder.JPQLNode node) {
// examing the node to find the candidate query
// ### this should actually be the primary SELECT instance
// resolved against the from variable declarations
JPQLNode from = node.findChildByID(JJTFROMITEM, true);
if (from == null) {
// OPENJPA-15 allow subquery without a FROMITEM
if (node.id == JJTSUBSELECT) {
from = node.findChildByID(JJTFROM, true);
}
else {
throw parseException(EX_USER, "no-from-clause", null, null);
}
}
for (int i = 0; i < from.children.length; i++) {
JPQLNode n = from.children[i];
if (n.id == JJTABSTRACTSCHEMANAME) {
// we simply return the first abstract schema child
// as resolved into a class
ClassMetaData cmd = resolveClassMetaData(n);
if (cmd != null)
return cmd;
// not a schema: treat it as a class
String cls = assertSchemaName(n);
if (cls == null)
throw parseException(EX_USER, "not-schema-name",
new Object[]{ root() }, null);
return getClassMetaData(cls, true);
}
// OPENJPA-15 support subquery's from clause do not start with
// identification_variable_declaration()
if (node.id == JJTSUBSELECT) {
if (n.id == JJTINNERJOIN) {
n = n.getChild(0);
}
if (n.id == JJTPATH) {
Path path = getPath(n);
ClassMetaData cmd = getFieldType(path.last());
if (cmd != null) {
return cmd;
}
else {
throw parseException(EX_USER, "no-alias",
new Object[]{ n }, null);
}
}
}
}
return null;
}
|
protected ClassLoader getClassLoader() {
// we don't resolve in the context of anything but ourselves
return getClass().getClassLoader();
}
|
protected Class getDeclaredVariableType(String name) {
ClassMetaData cmd = getMetaDataForAlias(name);
if (cmd != null)
return cmd.getDescribedType();
if (name != null && name.equals(ctx().schemaAlias))
return getCandidateType();
// JPQL has no declared variables
return null;
}
|
protected Localizer getLocalizer() {
return _loc;
}
|
protected JPQLExpressionBuilder.ParsedJPQL getParsedQuery() {
return ctx().parsed;
}
|
protected JPQLExpressionBuilder.ParsedJPQL getParsedQuery(String jpql) {
return new ParsedJPQL(jpql);
}
|
QueryExpressions getQueryExpressions() {
QueryExpressions exps = new QueryExpressions();
evalQueryOperation(exps);
Expression filter = null;
filter = and(evalFromClause(root().id == JJTSELECT), filter);
filter = and(evalWhereClause(), filter);
filter = and(evalSelectClause(exps), filter);
exps.filter = filter == null ? factory.emptyExpression() : filter;
evalGroupingClause(exps);
evalHavingClause(exps);
evalFetchJoins(exps);
evalSetClause(exps);
evalOrderingClauses(exps);
if (parameterTypes != null)
exps.parameterTypes = parameterTypes;
exps.accessPath = getAccessPath();
return exps;
}
|
protected Value getVariable(String id,
boolean bind) {
if (id == null)
return null;
return super.getVariable(id.toLowerCase(), bind);
}
Identification variables in JPQL are case insensitive, so lower-case
all variables we are going to bind. |
protected boolean isDeclaredVariable(String name) {
// JPQL doesn't support declaring variables
return false;
}
|
boolean isPath(JPQLExpressionBuilder.JPQLNode node) {
if (node.getChildCount() < 2)
return false;
final String name = firstChild(node).text;
if (name == null)
return false;
// handle the case where the class name is the alias
// for the candidate (we don't use variables for this)
if (getMetaDataForAlias(name) != null)
return true;
if (!isSeenVariable(name))
return false;
final Value var = getVariable(name, false);
if (var != null)
return isBound(var);
return false;
}
Check to see if the specific node is a path (vs. a schema name) |
protected boolean isSeendVariable(String id) {
return id != null && super.isSeenVariable(id.toLowerCase());
}
|
protected ClassMetaData resolveClassMetaData(JPQLExpressionBuilder.JPQLNode node) {
// handle looking up alias names
String schemaName = assertSchemaName(node);
ClassMetaData cmd = getClassMetaData(schemaName, false);
if (cmd != null)
return cmd;
// we might be referencing a collection field of a subquery's parent
if (isPath(node)) {
Path path = getPath(node);
return getFieldType(path.last());
}
// now run again to throw the correct exception
return getClassMetaData(schemaName, true);
}
|
protected void setImplicitTypes(Value val1,
Value val2,
Class expected) {
super.setImplicitTypes(val1, val2, expected);
// as well as setting the types for conversions, we also need to
// ensure that any parameters are declared with the correct type,
// since the JPA spec expects that these will be validated
Parameter param = val1 instanceof Parameter ? (Parameter) val1
: val2 instanceof Parameter ? (Parameter) val2 : null;
Path path = val1 instanceof Path ? (Path) val1
: val2 instanceof Path ? (Path) val2 : null;
// we only check for parameter-to-path comparisons
if (param == null || path == null || parameterTypes == null)
return;
FieldMetaData fmd = path.last();
if (fmd == null)
return;
Class type = path.isXPath() ? path.getType() : fmd.getType();
if (type == null)
return;
String paramName = param.getParameterName();
if (paramName == null)
return;
// make sure we have already declared the parameter
if (parameterTypes.containsKey(paramName))
parameterTypes.put(paramName, type);
}
|