mirror of https://github.com/apache/openjpa.git
OPENJPA-856 JPQ2 JPQL add support for entity type expression
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@736881 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c5736acdf4
commit
d49fdb1ea2
|
@ -79,6 +79,11 @@ abstract class AbstractVal
|
||||||
sql.append("1");
|
sql.append("1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void appendType(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
SQLBuffer sql) {
|
||||||
|
sql.append("1");
|
||||||
|
}
|
||||||
|
|
||||||
public void appendSize(Select sel, ExpContext ctx, ExpState state,
|
public void appendSize(Select sel, ExpContext ctx, ExpState state,
|
||||||
SQLBuffer sql) {
|
SQLBuffer sql) {
|
||||||
sql.append("1");
|
sql.append("1");
|
||||||
|
|
|
@ -91,7 +91,11 @@ class InExpression
|
||||||
public void appendTo(Select sel, ExpContext ctx, ExpState state,
|
public void appendTo(Select sel, ExpContext ctx, ExpState state,
|
||||||
SQLBuffer buf) {
|
SQLBuffer buf) {
|
||||||
InExpState istate = (InExpState) state;
|
InExpState istate = (InExpState) state;
|
||||||
_const.calculateValue(sel, ctx, istate.constantState, null, null);
|
if (_val instanceof Type)
|
||||||
|
_const.calculateValue(sel, ctx, istate.constantState, _val,
|
||||||
|
istate.valueState);
|
||||||
|
else
|
||||||
|
_const.calculateValue(sel, ctx, istate.constantState, null, null);
|
||||||
_val.calculateValue(sel, ctx, istate.valueState, null, null);
|
_val.calculateValue(sel, ctx, istate.valueState, null, null);
|
||||||
|
|
||||||
List list = null;
|
List list = null;
|
||||||
|
|
|
@ -247,6 +247,10 @@ public class JDBCExpressionFactory
|
||||||
return new Lit(val, ptype);
|
return new Lit(val, ptype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Literal newTypeLiteral(Object val, int ptype) {
|
||||||
|
return new TypeLit(val, ptype);
|
||||||
|
}
|
||||||
|
|
||||||
public Value getThis() {
|
public Value getThis() {
|
||||||
return new PCPath(_type);
|
return new PCPath(_type);
|
||||||
}
|
}
|
||||||
|
@ -396,6 +400,10 @@ public class JDBCExpressionFactory
|
||||||
return new Index((Val) val);
|
return new Index((Val) val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Value type(Value val) {
|
||||||
|
return new Type((Val) val);
|
||||||
|
}
|
||||||
|
|
||||||
public Value getObjectId(Value val) {
|
public Value getObjectId(Value val) {
|
||||||
if (val instanceof Const)
|
if (val instanceof Const)
|
||||||
return new ConstGetObjectId((Const) val);
|
return new ConstGetObjectId((Const) val);
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.util.ListIterator;
|
||||||
import org.apache.commons.lang.ObjectUtils;
|
import org.apache.commons.lang.ObjectUtils;
|
||||||
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
|
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
|
||||||
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
||||||
|
import org.apache.openjpa.jdbc.meta.Discriminator;
|
||||||
import org.apache.openjpa.jdbc.meta.FieldMapping;
|
import org.apache.openjpa.jdbc.meta.FieldMapping;
|
||||||
import org.apache.openjpa.jdbc.meta.ValueMapping;
|
import org.apache.openjpa.jdbc.meta.ValueMapping;
|
||||||
import org.apache.openjpa.jdbc.schema.Column;
|
import org.apache.openjpa.jdbc.schema.Column;
|
||||||
|
@ -814,6 +815,33 @@ public class PCPath
|
||||||
pstate.field.appendIndex(sql, sel, pstate.joins);;
|
pstate.field.appendIndex(sql, sel, pstate.joins);;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void appendType(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
SQLBuffer sql) {
|
||||||
|
Discriminator disc = null;
|
||||||
|
ClassMapping sup = _class;
|
||||||
|
while (sup.getMappedPCSuperclassMapping() != null)
|
||||||
|
sup = sup.getMappedPCSuperclassMapping();
|
||||||
|
|
||||||
|
disc = sup.getDiscriminator();
|
||||||
|
|
||||||
|
Column[] cols = null;
|
||||||
|
if (disc != null)
|
||||||
|
cols = disc.getColumns();
|
||||||
|
else
|
||||||
|
cols = getColumns(state);
|
||||||
|
|
||||||
|
if (cols == null) {
|
||||||
|
sql.append("1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < cols.length; i++) {
|
||||||
|
if (i > 0)
|
||||||
|
sql.append(", ");
|
||||||
|
sql.append(sel.getColumnAlias(cols[i], state.joins));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void appendSize(Select sel, ExpContext ctx, ExpState state,
|
public void appendSize(Select sel, ExpContext ctx, ExpState state,
|
||||||
SQLBuffer sql) {
|
SQLBuffer sql) {
|
||||||
PathExpState pstate = (PathExpState) state;
|
PathExpState pstate = (PathExpState) state;
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
||||||
|
import org.apache.openjpa.jdbc.meta.Discriminator;
|
||||||
import org.apache.openjpa.jdbc.sql.SQLBuffer;
|
import org.apache.openjpa.jdbc.sql.SQLBuffer;
|
||||||
import org.apache.openjpa.jdbc.sql.Select;
|
import org.apache.openjpa.jdbc.sql.Select;
|
||||||
import org.apache.openjpa.kernel.Filters;
|
import org.apache.openjpa.kernel.Filters;
|
||||||
|
@ -82,6 +83,12 @@ public class Param
|
||||||
return Filters.convert(params[_idx], getType());
|
return Filters.convert(params[_idx], getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object getValue(ExpContext ctx, ExpState state) {
|
||||||
|
ParamExpState pstate = (ParamExpState) state;
|
||||||
|
return (pstate.discValue != null) ? pstate.discValue :
|
||||||
|
getValue(ctx.params);
|
||||||
|
}
|
||||||
|
|
||||||
public Object getSQLValue(Select sel, ExpContext ctx, ExpState state) {
|
public Object getSQLValue(Select sel, ExpContext ctx, ExpState state) {
|
||||||
return ((ParamExpState) state).sqlValue;
|
return ((ParamExpState) state).sqlValue;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +104,10 @@ public class Param
|
||||||
extends ConstExpState {
|
extends ConstExpState {
|
||||||
|
|
||||||
public Object sqlValue = null;
|
public Object sqlValue = null;
|
||||||
public int otherLength = 1;
|
public int otherLength = 1;
|
||||||
|
public ClassMapping mapping = null;
|
||||||
|
public Discriminator disc = null;
|
||||||
|
public Object discValue = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void calculateValue(Select sel, ExpContext ctx, ExpState state,
|
public void calculateValue(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
@ -108,6 +118,14 @@ public class Param
|
||||||
if (other != null && !_container) {
|
if (other != null && !_container) {
|
||||||
pstate.sqlValue = other.toDataStoreValue(sel, ctx, otherState, val);
|
pstate.sqlValue = other.toDataStoreValue(sel, ctx, otherState, val);
|
||||||
pstate.otherLength = other.length(sel, ctx, otherState);
|
pstate.otherLength = other.length(sel, ctx, otherState);
|
||||||
|
if (other instanceof Type) {
|
||||||
|
pstate.mapping = ctx.store.getConfiguration().
|
||||||
|
getMappingRepositoryInstance().getMapping((Class) val,
|
||||||
|
ctx.store.getContext().getClassLoader(), true);
|
||||||
|
pstate.disc = pstate.mapping.getDiscriminator();
|
||||||
|
pstate.discValue = pstate.disc != null ? pstate.disc.getValue()
|
||||||
|
: null;
|
||||||
|
}
|
||||||
} else if (ImplHelper.isManageable(val)) {
|
} else if (ImplHelper.isManageable(val)) {
|
||||||
ClassMapping mapping = ctx.store.getConfiguration().
|
ClassMapping mapping = ctx.store.getConfiguration().
|
||||||
getMappingRepositoryInstance().getMapping(val.getClass(),
|
getMappingRepositoryInstance().getMapping(val.getClass(),
|
||||||
|
@ -125,6 +143,10 @@ public class Param
|
||||||
if (pstate.otherLength > 1)
|
if (pstate.otherLength > 1)
|
||||||
sql.appendValue(((Object[]) pstate.sqlValue)[index],
|
sql.appendValue(((Object[]) pstate.sqlValue)[index],
|
||||||
pstate.getColumn(index));
|
pstate.getColumn(index));
|
||||||
|
else if (pstate.cols != null)
|
||||||
|
sql.appendValue(pstate.sqlValue, pstate.getColumn(index));
|
||||||
|
else if (pstate.discValue != null)
|
||||||
|
sql.appendValue(pstate.discValue);
|
||||||
else
|
else
|
||||||
sql.appendValue(pstate.sqlValue, pstate.getColumn(index));
|
sql.appendValue(pstate.sqlValue, pstate.getColumn(index));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.jdbc.kernel.exps;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
||||||
|
import org.apache.openjpa.jdbc.meta.Discriminator;
|
||||||
|
import org.apache.openjpa.jdbc.sql.Result;
|
||||||
|
import org.apache.openjpa.jdbc.sql.SQLBuffer;
|
||||||
|
import org.apache.openjpa.jdbc.sql.Select;
|
||||||
|
import org.apache.openjpa.util.InternalException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity Type expression.
|
||||||
|
*
|
||||||
|
* @author Catalina Wei
|
||||||
|
*/
|
||||||
|
class Type
|
||||||
|
extends UnaryOp {
|
||||||
|
|
||||||
|
Discriminator _disc = null;
|
||||||
|
|
||||||
|
public Type(Val val) {
|
||||||
|
super(val);
|
||||||
|
setMetaData(val.getMetaData());
|
||||||
|
_disc = ((ClassMapping) getMetaData()).getDiscriminator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpState initialize(Select sel, ExpContext ctx, int flags) {
|
||||||
|
// initialize the value with a null test
|
||||||
|
return initializeValue(sel, ctx, NULL_CMP);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object load(ExpContext ctx, ExpState state, Result res)
|
||||||
|
throws SQLException {
|
||||||
|
Object type = getValue().load(ctx, state, res);
|
||||||
|
return type.getClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void calculateValue(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
Val other, ExpState otherState) {
|
||||||
|
super.calculateValue(sel, ctx, state, null, null);
|
||||||
|
if (_disc != null)
|
||||||
|
_disc.select(sel, (ClassMapping) getMetaData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void select(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
boolean pks) {
|
||||||
|
getValue().select(sel, ctx, state, pks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void appendTo(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
SQLBuffer sql, int index) {
|
||||||
|
getValue().calculateValue(sel, ctx, state, null, null);
|
||||||
|
getValue().appendType(sel, ctx, state, sql);
|
||||||
|
sel.append(sql, state.joins);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class getType(Class c) {
|
||||||
|
return Class.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getOperator() {
|
||||||
|
// since we override appendTo(), this method should never be called
|
||||||
|
throw new InternalException();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.jdbc.kernel.exps;
|
||||||
|
|
||||||
|
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
||||||
|
import org.apache.openjpa.jdbc.meta.Discriminator;
|
||||||
|
import org.apache.openjpa.jdbc.sql.SQLBuffer;
|
||||||
|
import org.apache.openjpa.jdbc.sql.Select;
|
||||||
|
import org.apache.openjpa.kernel.Filters;
|
||||||
|
import org.apache.openjpa.kernel.exps.Literal;
|
||||||
|
import org.apache.openjpa.meta.JavaTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type literal value.
|
||||||
|
*
|
||||||
|
* @author Catalina Wei
|
||||||
|
*/
|
||||||
|
public class TypeLit
|
||||||
|
extends Const
|
||||||
|
implements Literal {
|
||||||
|
|
||||||
|
private Object _val;
|
||||||
|
private int _ptype;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor. Supply literal value.
|
||||||
|
*/
|
||||||
|
public TypeLit(Object val, int ptype) {
|
||||||
|
_val = val;
|
||||||
|
_ptype = ptype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getType() {
|
||||||
|
return (_val == null) ? Object.class : _val.getClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImplicitType(Class type) {
|
||||||
|
_val = Filters.convert(_val, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getParseType() {
|
||||||
|
return _ptype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Object val) {
|
||||||
|
_val = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue(Object[] params) {
|
||||||
|
return getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpState initialize(Select sel, ExpContext ctx, int flags) {
|
||||||
|
return new LitExpState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expression state.
|
||||||
|
*/
|
||||||
|
private static class LitExpState
|
||||||
|
extends ConstExpState {
|
||||||
|
|
||||||
|
public Object sqlValue;
|
||||||
|
public int otherLength;
|
||||||
|
public ClassMapping mapping = null;
|
||||||
|
public Discriminator disc = null;
|
||||||
|
public Object discValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void calculateValue(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
Val other, ExpState otherState) {
|
||||||
|
super.calculateValue(sel, ctx, state, other, otherState);
|
||||||
|
LitExpState lstate = (LitExpState) state;
|
||||||
|
lstate.mapping = (ClassMapping) getMetaData();
|
||||||
|
lstate.disc = lstate.mapping.getDiscriminator();
|
||||||
|
lstate.discValue = lstate.disc != null ? lstate.disc.getValue() :
|
||||||
|
null;
|
||||||
|
sel.select(((ClassMapping) getMetaData()).getPrimaryKeyColumns(),
|
||||||
|
lstate.joins);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void appendTo(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
SQLBuffer sql, int index) {
|
||||||
|
LitExpState lstate = (LitExpState) state;
|
||||||
|
if (lstate.otherLength > 1)
|
||||||
|
sql.appendValue(((Object[]) lstate.sqlValue)[index],
|
||||||
|
lstate.getColumn(index));
|
||||||
|
else {
|
||||||
|
if (lstate.discValue != null)
|
||||||
|
sql.append(getDiscriminator(lstate));
|
||||||
|
else
|
||||||
|
sql.append("1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDiscriminator(LitExpState lstate) {
|
||||||
|
StringBuffer disc = new StringBuffer(lstate.discValue.toString());
|
||||||
|
switch(lstate.disc.getJavaType()) {
|
||||||
|
case JavaTypes.INT:
|
||||||
|
return disc.toString();
|
||||||
|
case JavaTypes.CHAR:
|
||||||
|
case JavaTypes.STRING:
|
||||||
|
default:
|
||||||
|
return disc.insert(0, "'").append("'").toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -152,6 +152,12 @@ public interface Val
|
||||||
public void appendIndex(Select sel, ExpContext ctx, ExpState state,
|
public void appendIndex(Select sel, ExpContext ctx, ExpState state,
|
||||||
SQLBuffer sql);
|
SQLBuffer sql);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the SQL checking the type of this value.
|
||||||
|
*/
|
||||||
|
public void appendType(Select sel, ExpContext ctx, ExpState state,
|
||||||
|
SQLBuffer sql);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append the SQL checking the size of this value.
|
* Append the SQL checking the size of this value.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -862,6 +862,10 @@ public class FieldMapping
|
||||||
assertStrategy().appendIndex(sql, sel, joins);
|
assertStrategy().appendIndex(sql, sel, joins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void appendType(SQLBuffer sql, Select sel, Joins joins) {
|
||||||
|
assertStrategy().appendType(sql, sel, joins);
|
||||||
|
}
|
||||||
|
|
||||||
public Joins join(Joins joins, boolean forceOuter) {
|
public Joins join(Joins joins, boolean forceOuter) {
|
||||||
return assertStrategy().join(joins, forceOuter);
|
return assertStrategy().join(joins, forceOuter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,6 +185,11 @@ public interface FieldStrategy
|
||||||
*/
|
*/
|
||||||
public void appendIndex(SQLBuffer sql, Select sel, Joins joins);
|
public void appendIndex(SQLBuffer sql, Select sel, Joins joins);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the entity discriminator value to the given statement.
|
||||||
|
*/
|
||||||
|
public void appendType(SQLBuffer sql, Select sel, Joins joins);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Join this value to the class table. Does nothing by default.
|
* Join this value to the class table. Does nothing by default.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -139,6 +139,10 @@ public abstract class AbstractFieldStrategy
|
||||||
sql.append("1");
|
sql.append("1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void appendType(SQLBuffer sql, Select sel, Joins joins) {
|
||||||
|
sql.append("1");
|
||||||
|
}
|
||||||
|
|
||||||
public Joins join(Joins joins, boolean forceOuter) {
|
public Joins join(Joins joins, boolean forceOuter) {
|
||||||
return joins;
|
return joins;
|
||||||
}
|
}
|
||||||
|
|
|
@ -402,6 +402,13 @@ public interface ExpressionFactory {
|
||||||
*/
|
*/
|
||||||
public Value index(Value target);
|
public Value index(Value target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the type/class of the given value.
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
public Value type(Value target);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return distinct values of the given value. This is typically used
|
* Return distinct values of the given value. This is typically used
|
||||||
* within aggregates, for example: max(distinct(path))
|
* within aggregates, for example: max(distinct(path))
|
||||||
|
@ -445,4 +452,10 @@ public interface ExpressionFactory {
|
||||||
* Return a nullif expression
|
* Return a nullif expression
|
||||||
*/
|
*/
|
||||||
public Value nullIfExpression(Value val1, Value val2);
|
public Value nullIfExpression(Value val1, Value val2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a value representing the given constant, which will be
|
||||||
|
* a {@link Number}, {@link String}, or {@link Boolean} instance.
|
||||||
|
*/
|
||||||
|
public Literal newTypeLiteral(Object val, int parseType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -480,6 +480,10 @@ public class InMemoryExpressionFactory
|
||||||
return new Lit(val, parseType);
|
return new Lit(val, parseType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Literal newTypeLiteral(Object val, int parseType) {
|
||||||
|
return new TypeLit(val, parseType);
|
||||||
|
}
|
||||||
|
|
||||||
public Value getThis() {
|
public Value getThis() {
|
||||||
return new This();
|
return new This();
|
||||||
}
|
}
|
||||||
|
@ -635,6 +639,10 @@ public class InMemoryExpressionFactory
|
||||||
return new Index((Val) val);
|
return new Index((Val) val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Value type(Value val) {
|
||||||
|
return new Type((Val) val);
|
||||||
|
}
|
||||||
|
|
||||||
public Value getObjectId(Value val) {
|
public Value getObjectId(Value val) {
|
||||||
return new GetObjectId((Val) val);
|
return new GetObjectId((Val) val);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ public interface Literal
|
||||||
public static final int TYPE_BOOLEAN = 2;
|
public static final int TYPE_BOOLEAN = 2;
|
||||||
public static final int TYPE_STRING = 3;
|
public static final int TYPE_STRING = 3;
|
||||||
public static final int TYPE_SQ_STRING = 4; // single-quoted string
|
public static final int TYPE_SQ_STRING = 4; // single-quoted string
|
||||||
|
public static final int TYPE_CLASS = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value of this literal.
|
* The value of this literal.
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.kernel.exps;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.openjpa.kernel.StoreContext;
|
||||||
|
|
||||||
|
import serp.util.Numbers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the entity type.
|
||||||
|
*
|
||||||
|
* @author Catalina Wei
|
||||||
|
*/
|
||||||
|
class Type extends Val {
|
||||||
|
|
||||||
|
private final Val _val;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor. Provide target string and the arguments to the
|
||||||
|
* indexOf method.
|
||||||
|
*/
|
||||||
|
public Type(Val val) {
|
||||||
|
_val = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getType() {
|
||||||
|
return Class.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImplicitType(Class type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object eval(Object candidate, Object orig,
|
||||||
|
StoreContext ctx, Object[] params) {
|
||||||
|
_val.eval(candidate, orig, ctx, params);
|
||||||
|
return _val.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void acceptVisit(ExpressionVisitor visitor) {
|
||||||
|
visitor.enter(this);
|
||||||
|
_val.acceptVisit(visitor);
|
||||||
|
visitor.exit(this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.kernel.exps;
|
||||||
|
|
||||||
|
import org.apache.openjpa.kernel.Filters;
|
||||||
|
import org.apache.openjpa.kernel.StoreContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a type literal.
|
||||||
|
*
|
||||||
|
* @author Catalina Wei
|
||||||
|
*/
|
||||||
|
class TypeLit
|
||||||
|
extends Val
|
||||||
|
implements Literal {
|
||||||
|
|
||||||
|
private Object _val;
|
||||||
|
private final int _ptype;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor. Provide constant value.
|
||||||
|
*/
|
||||||
|
public TypeLit(Object val, int ptype) {
|
||||||
|
_val = val;
|
||||||
|
_ptype = ptype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Object val) {
|
||||||
|
_val = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getParseType() {
|
||||||
|
return _ptype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue(Object[] parameters) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getType() {
|
||||||
|
return (_val == null) ? Object.class : _val.getClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImplicitType(Class type) {
|
||||||
|
_val = Filters.convert(_val, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object eval(Object candidate, Object orig,
|
||||||
|
StoreContext ctx, Object[] params) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
|
@ -330,14 +330,23 @@ public class JPQLExpressionBuilder
|
||||||
if (aliasNode != null)
|
if (aliasNode != null)
|
||||||
proj.setAlias(alias);
|
proj.setAlias(alias);
|
||||||
exps.projections[i] = proj;
|
exps.projections[i] = proj;
|
||||||
exps.projectionClauses[i] = aliasNode == null ?
|
exps.projectionClauses[i] = aliasNode != null ? alias :
|
||||||
assemble(node.id == JJTSCALAREXPRESSION ? firstChild(node)
|
projectionClause(node.id == JJTSCALAREXPRESSION ?
|
||||||
: node) : alias;
|
firstChild(node) : node);
|
||||||
exps.projectionAliases[i] = alias;
|
exps.projectionAliases[i] = alias;
|
||||||
}
|
}
|
||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String projectionClause(JPQLNode node) {
|
||||||
|
switch (node.id) {
|
||||||
|
case JJTTYPE:
|
||||||
|
return projectionClause(firstChild(node));
|
||||||
|
default:
|
||||||
|
return assemble(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void evalQueryOperation(QueryExpressions exps) {
|
private void evalQueryOperation(QueryExpressions exps) {
|
||||||
// determine whether we want to select, delete, or update
|
// determine whether we want to select, delete, or update
|
||||||
if (root().id == JJTSELECT || root().id == JJTSUBSELECT)
|
if (root().id == JJTSELECT || root().id == JJTSUBSELECT)
|
||||||
|
@ -746,7 +755,10 @@ public class JPQLExpressionBuilder
|
||||||
return eval(onlyChild(node));
|
return eval(onlyChild(node));
|
||||||
|
|
||||||
case JJTTYPE:
|
case JJTTYPE:
|
||||||
return eval(onlyChild(node));
|
return getType(onlyChild(node));
|
||||||
|
|
||||||
|
case JJTTYPELITERAL:
|
||||||
|
return getTypeLiteral(node);
|
||||||
|
|
||||||
case JJTCLASSNAME:
|
case JJTCLASSNAME:
|
||||||
return getPathOrConstant(node);
|
return getPathOrConstant(node);
|
||||||
|
@ -754,10 +766,10 @@ public class JPQLExpressionBuilder
|
||||||
case JJTCASE:
|
case JJTCASE:
|
||||||
return eval(onlyChild(node));
|
return eval(onlyChild(node));
|
||||||
|
|
||||||
case JJTSCASE:
|
case JJTSIMPLECASE:
|
||||||
return getSimpleCaseExpression(node);
|
return getSimpleCaseExpression(node);
|
||||||
|
|
||||||
case JJTGCASE:
|
case JJTGENERALCASE:
|
||||||
return getGeneralCaseExpression(node);
|
return getGeneralCaseExpression(node);
|
||||||
|
|
||||||
case JJTWHEN:
|
case JJTWHEN:
|
||||||
|
@ -814,6 +826,10 @@ public class JPQLExpressionBuilder
|
||||||
case JJTPOSITIONALINPUTPARAMETER:
|
case JJTPOSITIONALINPUTPARAMETER:
|
||||||
return getParameter(node.text, true);
|
return getParameter(node.text, true);
|
||||||
|
|
||||||
|
case JJTCOLLECTIONPARAMETER:
|
||||||
|
// TODO: support collection valued parameters
|
||||||
|
return getParameter(onlyChild(node).text, true);
|
||||||
|
|
||||||
case JJTOR: // x OR y
|
case JJTOR: // x OR y
|
||||||
return factory.or(getExpression(left(node)),
|
return factory.or(getExpression(left(node)),
|
||||||
getExpression(right(node)));
|
getExpression(right(node)));
|
||||||
|
@ -892,14 +908,19 @@ public class JPQLExpressionBuilder
|
||||||
factory.lessThanEqual(val1, val3)));
|
factory.lessThanEqual(val1, val3)));
|
||||||
|
|
||||||
case JJTIN: // x.field [NOT] IN ('a', 'b', 'c')
|
case JJTIN: // x.field [NOT] IN ('a', 'b', 'c')
|
||||||
|
// TYPE(x...) [NOT] IN (entityTypeLiteral1,...)
|
||||||
Expression inExp = null;
|
Expression inExp = null;
|
||||||
Iterator inIterator = node.iterator();
|
Iterator inIterator = node.iterator();
|
||||||
// the first child is the path
|
// the first child is the path
|
||||||
val1 = getValue((JPQLNode) inIterator.next());
|
JPQLNode first = (JPQLNode) inIterator.next();
|
||||||
|
val1 = getValue(first);
|
||||||
|
|
||||||
while (inIterator.hasNext()) {
|
while (inIterator.hasNext()) {
|
||||||
val2 = getValue((JPQLNode) inIterator.next());
|
JPQLNode next = (JPQLNode) inIterator.next();
|
||||||
|
if (first.id == JJTTYPE && next.id == JJTTYPELITERAL)
|
||||||
|
val2 = getTypeLiteral(next);
|
||||||
|
else
|
||||||
|
val2 = getValue(next);
|
||||||
|
|
||||||
// special case for <value> IN (<subquery>) or
|
// special case for <value> IN (<subquery>) or
|
||||||
// <value> IN (<single value>)
|
// <value> IN (<single value>)
|
||||||
|
@ -1360,6 +1381,21 @@ public class JPQLExpressionBuilder
|
||||||
} else if (val instanceof Path) {
|
} else if (val instanceof Path) {
|
||||||
return (Path) val;
|
return (Path) val;
|
||||||
} else if (val instanceof Value) {
|
} else if (val instanceof Value) {
|
||||||
|
if (val.isVariable()) {
|
||||||
|
// can be an entity type literal
|
||||||
|
Class c = resolver.classForName(name, null);
|
||||||
|
if (c != null) {
|
||||||
|
Value lit = factory.newTypeLiteral(c, Literal.TYPE_CLASS);
|
||||||
|
Class<?> candidate = getCandidateType();
|
||||||
|
ClassMetaData can = getClassMetaData(candidate.getName(), false);
|
||||||
|
ClassMetaData meta = getClassMetaData(name, false);
|
||||||
|
if (candidate.isAssignableFrom(c))
|
||||||
|
lit.setMetaData(meta);
|
||||||
|
else
|
||||||
|
lit.setMetaData(can);
|
||||||
|
return lit;
|
||||||
|
}
|
||||||
|
}
|
||||||
return (Value) val;
|
return (Value) val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1367,6 +1403,24 @@ public class JPQLExpressionBuilder
|
||||||
new Object[]{ name }, null);
|
new Object[]{ name }, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Value getTypeLiteral(JPQLNode node) {
|
||||||
|
JPQLNode type = onlyChild(node);
|
||||||
|
final String name = type.text;
|
||||||
|
final Value val = getVariable(name, false);
|
||||||
|
|
||||||
|
if (val instanceof Value && val.isVariable()) {
|
||||||
|
Class c = resolver.classForName(name, null);
|
||||||
|
if (c != null) {
|
||||||
|
Value typeLit = factory.newTypeLiteral(c, Literal.TYPE_CLASS);
|
||||||
|
typeLit.setMetaData(getClassMetaData(name, false));
|
||||||
|
return typeLit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw parseException(EX_USER, "not-type-literal",
|
||||||
|
new Object[]{ name }, null);
|
||||||
|
}
|
||||||
|
|
||||||
private Value getPathOrConstant(JPQLNode node) {
|
private Value getPathOrConstant(JPQLNode node) {
|
||||||
// first check to see if the path is an enum or static field, and
|
// first check to see if the path is an enum or static field, and
|
||||||
// if so, load it
|
// if so, load it
|
||||||
|
@ -1394,6 +1448,36 @@ public class JPQLExpressionBuilder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process type_discriminator
|
||||||
|
* type_discriminator ::=
|
||||||
|
* TYPE(identification_variable |
|
||||||
|
* single_valued_object_path_expression |
|
||||||
|
* input_parameter )
|
||||||
|
*/
|
||||||
|
private Value getType(JPQLNode node) {
|
||||||
|
switch (node.id) {
|
||||||
|
case JJTIDENTIFIER:
|
||||||
|
return factory.type(getValue(node));
|
||||||
|
|
||||||
|
case JJTNAMEDINPUTPARAMETER:
|
||||||
|
return factory.type(getParameter(node.text, false));
|
||||||
|
|
||||||
|
case JJTPOSITIONALINPUTPARAMETER:
|
||||||
|
return factory.type(getParameter(node.text, true));
|
||||||
|
|
||||||
|
default:
|
||||||
|
// TODO: enforce jpa2.0 spec rules.
|
||||||
|
// A single_valued_object_field is designated by the name of
|
||||||
|
// an association field in a one-to-one or many-to-one relationship
|
||||||
|
// or a field of embeddable class type.
|
||||||
|
// The type of a single_valued_object_field is the abstract schema
|
||||||
|
// type of the related entity or embeddable class
|
||||||
|
Value path = getPath(node, false, true);
|
||||||
|
return factory.type(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Path getPath(JPQLNode node) {
|
private Path getPath(JPQLNode node) {
|
||||||
return getPath(node, false, true);
|
return getPath(node, false, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -745,19 +745,26 @@ void between_expression() #BETWEEN : { }
|
||||||
|
|
||||||
void in_expression() #IN : { }
|
void in_expression() #IN : { }
|
||||||
{
|
{
|
||||||
(path() | scalar_function()) [ LOOKAHEAD(1) <NOT> { jjtThis.not = true; }] <IN>
|
(path() | scalar_function() | type_discriminator()) [ LOOKAHEAD(1) <NOT> { jjtThis.not = true; }] <IN>
|
||||||
"(" (literal_or_param()
|
("(" (literal_or_param()
|
||||||
(<COMMA> (literal_or_param()))* | subquery())
|
(<COMMA> (literal_or_param()))* | subquery())
|
||||||
")"
|
")"
|
||||||
|
| collection_valued_input_parameter()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void entity_type_literal() #TYPELITERAL : { }
|
||||||
|
{
|
||||||
|
identification_variable()
|
||||||
|
}
|
||||||
|
|
||||||
void literal_or_param() : { }
|
void literal_or_param() : { }
|
||||||
{
|
{
|
||||||
(numeric_literal()
|
(numeric_literal()
|
||||||
| string_literal()
|
| string_literal()
|
||||||
| boolean_literal()
|
| boolean_literal()
|
||||||
| input_parameter())
|
| input_parameter()
|
||||||
|
| entity_type_literal())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -941,46 +948,51 @@ void arithmetic_factor() : { }
|
||||||
LOOKAHEAD(2) "(" arithmetic_expression() ")" |
|
LOOKAHEAD(2) "(" arithmetic_expression() ")" |
|
||||||
functions_returning_numerics() |
|
functions_returning_numerics() |
|
||||||
aggregate_select_expression() |
|
aggregate_select_expression() |
|
||||||
|
LOOKAHEAD(case_expression()) case_expression() |
|
||||||
subquery()
|
subquery()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void qualified_path() #QPATH : { }
|
void qualified_path() #QUALIFIEDPATH : { }
|
||||||
{
|
{
|
||||||
general_identification_variable() (LOOKAHEAD(2) <DOT> path_component())+
|
general_identification_variable() (LOOKAHEAD(2) <DOT> path_component())+
|
||||||
}
|
}
|
||||||
|
|
||||||
void qualified_identification_variable() #QIDENTIFIER : { }
|
void qualified_identification_variable() #QUALIFIEDIDENTIFIER : { }
|
||||||
{
|
{
|
||||||
( <KEY> "(" identification_variable() ")" #KEY
|
( <KEY> "(" identification_variable() ")" #KEY(1)
|
||||||
| <VALUE> "(" identification_variable() ")" #VALUE
|
| <VALUE> "(" identification_variable() ")" #VALUE(1)
|
||||||
| <ENTRY> "(" identification_variable() ")" #ENTRY
|
| <ENTRY> "(" identification_variable() ")" #ENTRY(1)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
void general_identification_variable() #GIDENTIFIER : { }
|
void general_identification_variable() #GENERALIDENTIFIER : { }
|
||||||
{
|
{
|
||||||
( <KEY> "(" identification_variable() ")" #KEY
|
( <KEY> "(" identification_variable() ")" #KEY(1)
|
||||||
| <VALUE> "(" identification_variable() ")" #VALUE
|
| <VALUE> "(" identification_variable() ")" #VALUE(1)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
void entity_type_comp() : { }
|
void entity_type_comp() : { }
|
||||||
{
|
{
|
||||||
entity_type_expression()
|
(entity_type_expression() | entity_type_literal())
|
||||||
( <EQ> entity_type_expression() #EQUALS(2)
|
( <EQ> (entity_type_expression() | entity_type_literal()) #EQUALS(2)
|
||||||
| <NE> entity_type_expression() #NOTEQUALS(2)
|
| <NE> (entity_type_expression() | entity_type_literal()) #NOTEQUALS(2)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
void entity_type_expression() #TYPE : { }
|
void type_discriminator() #TYPE : { }
|
||||||
{
|
{
|
||||||
<TYPE> "(" (LOOKAHEAD(identification_variable()) identification_variable()
|
<TYPE> "(" (LOOKAHEAD(path()) path()
|
||||||
| LOOKAHEAD(path()) path()
|
|
||||||
| LOOKAHEAD(general_identification_variable()) general_identification_variable()
|
| LOOKAHEAD(general_identification_variable()) general_identification_variable()
|
||||||
|
| LOOKAHEAD(identification_variable()) identification_variable()
|
||||||
| LOOKAHEAD(input_parameter()) input_parameter())
|
| LOOKAHEAD(input_parameter()) input_parameter())
|
||||||
")" |
|
")"
|
||||||
classname() #TYPE_LITERAL |
|
}
|
||||||
|
|
||||||
|
void entity_type_expression(): { }
|
||||||
|
{
|
||||||
|
type_discriminator() |
|
||||||
input_parameter()
|
input_parameter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -990,7 +1002,7 @@ void scalar_expression() #SCALAREXPRESSION : { }
|
||||||
LOOKAHEAD(case_expression()) case_expression() |
|
LOOKAHEAD(case_expression()) case_expression() |
|
||||||
LOOKAHEAD(string_primary()) string_primary() |
|
LOOKAHEAD(string_primary()) string_primary() |
|
||||||
LOOKAHEAD(datetime_primary()) datetime_primary() |
|
LOOKAHEAD(datetime_primary()) datetime_primary() |
|
||||||
LOOKAHEAD(enum_primary()) enum_primary()
|
LOOKAHEAD(enum_primary()) enum_primary() |
|
||||||
LOOKAHEAD(entity_type_expression()) entity_type_expression()
|
LOOKAHEAD(entity_type_expression()) entity_type_expression()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1004,29 +1016,31 @@ void case_expression() #CASE : { }
|
||||||
<NULLIF> nullif_expression()
|
<NULLIF> nullif_expression()
|
||||||
}
|
}
|
||||||
|
|
||||||
void general_case_expression() #GCASE : { }
|
void general_case_expression() #GENERALCASE : { }
|
||||||
{
|
{
|
||||||
(when_clause())+
|
(when_clause())+
|
||||||
<ELSE> scalar_expression()
|
<ELSE> (LOOKAHEAD(2) scalar_expression() | entity_type_literal())
|
||||||
<END>
|
<END>
|
||||||
}
|
}
|
||||||
|
|
||||||
void when_clause() #WHEN : { }
|
void when_clause() #WHEN : { }
|
||||||
{
|
{
|
||||||
<WHEN> conditional_expression() <THEN> scalar_expression()
|
<WHEN> conditional_expression()
|
||||||
|
<THEN> (LOOKAHEAD(2) scalar_expression() | entity_type_literal())
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_case_expression() #SCASE : { }
|
void simple_case_expression() #SIMPLECASE : { }
|
||||||
{
|
{
|
||||||
(LOOKAHEAD(2) path() | entity_type_expression())
|
(LOOKAHEAD(type_discriminator()) type_discriminator() | LOOKAHEAD(path()) path())
|
||||||
(simple_when_clause())+
|
(simple_when_clause())+
|
||||||
<ELSE> scalar_expression()
|
<ELSE> (LOOKAHEAD(2) scalar_expression() | entity_type_literal())
|
||||||
<END>
|
<END>
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_when_clause() #WHENSCALAR : { }
|
void simple_when_clause() #WHENSCALAR : { }
|
||||||
{
|
{
|
||||||
<WHEN> scalar_expression() <THEN> scalar_expression()
|
<WHEN> (LOOKAHEAD(2) scalar_expression() | entity_type_literal())
|
||||||
|
<THEN> (LOOKAHEAD(2) scalar_expression() | entity_type_literal())
|
||||||
}
|
}
|
||||||
|
|
||||||
void coalesce_expression() #COALESCE : { }
|
void coalesce_expression() #COALESCE : { }
|
||||||
|
@ -1409,6 +1423,12 @@ void input_parameter() : { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void collection_valued_input_parameter() #COLLECTIONPARAMETER: { }
|
||||||
|
{
|
||||||
|
named_input_parameter() | positional_input_parameter()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void named_input_parameter() #NAMEDINPUTPARAMETER :
|
void named_input_parameter() #NAMEDINPUTPARAMETER :
|
||||||
{ Token t; }
|
{ Token t; }
|
||||||
{
|
{
|
||||||
|
|
|
@ -71,4 +71,5 @@ query-extensions-error: This JPQL query uses non-standard OpenJPA \
|
||||||
openjpa.Compatibility configuration setting is configured to disallow \
|
openjpa.Compatibility configuration setting is configured to disallow \
|
||||||
JPQL extensions.
|
JPQL extensions.
|
||||||
jpql-parse-error: "{1}" while parsing JPQL "{0}". See nested stack trace for \
|
jpql-parse-error: "{1}" while parsing JPQL "{0}". See nested stack trace for \
|
||||||
original parse error.
|
original parse error.
|
||||||
|
not-type-literal: The specified node ("{0}") is not a valid entity type literal.
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.persistence.jpql.expressions;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
import org.apache.openjpa.persistence.common.apps.*;
|
||||||
|
import org.apache.openjpa.persistence.common.utils.AbstractTestCase;
|
||||||
|
|
||||||
|
public class TestEntityTypeExpression extends AbstractTestCase {
|
||||||
|
|
||||||
|
private int userid1, userid2, userid3, userid4, userid5, userid6;
|
||||||
|
|
||||||
|
public TestEntityTypeExpression(String name) {
|
||||||
|
super(name, "jpqlclausescactusapp");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUp() {
|
||||||
|
deleteAll(CompUser.class);
|
||||||
|
EntityManager em = currentEntityManager();
|
||||||
|
startTx(em);
|
||||||
|
|
||||||
|
Address[] add = new Address[]{
|
||||||
|
new Address("43 Sansome", "SF", "United-Kingdom", "94104"),
|
||||||
|
new Address("24 Mink", "ANTIOCH", "USA", "94513"),
|
||||||
|
new Address("23 Ogbete", "CoalCamp", "NIGERIA", "00000"),
|
||||||
|
new Address("10 Wilshire", "Worcester", "CANADA", "80080"),
|
||||||
|
new Address("23 Bellflower", "Ogui", null, "02000"),
|
||||||
|
new Address("22 Montgomery", "SF", null, "50054") };
|
||||||
|
|
||||||
|
CompUser user1 = createUser("Seetha", "MAC", add[0], 36, true);
|
||||||
|
CompUser user2 = createUser("Shannon ", "PC", add[1], 36, false);
|
||||||
|
CompUser user3 = createUser("Ugo", "PC", add[2], 19, true);
|
||||||
|
CompUser user4 = createUser("_Jacob", "LINUX", add[3], 10, true);
|
||||||
|
CompUser user5 = createUser("Famzy", "UNIX", add[4], 29, false);
|
||||||
|
CompUser user6 = createUser("Shade", "UNIX", add[5], 23, false);
|
||||||
|
|
||||||
|
em.persist(user1);
|
||||||
|
userid1 = user1.getUserid();
|
||||||
|
em.persist(user2);
|
||||||
|
userid2 = user2.getUserid();
|
||||||
|
em.persist(user3);
|
||||||
|
userid3 = user3.getUserid();
|
||||||
|
em.persist(user4);
|
||||||
|
userid4 = user4.getUserid();
|
||||||
|
em.persist(user5);
|
||||||
|
userid5 = user5.getUserid();
|
||||||
|
em.persist(user6);
|
||||||
|
userid6 = user6.getUserid();
|
||||||
|
|
||||||
|
endTx(em);
|
||||||
|
endEm(em);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void testTypeExpression() {
|
||||||
|
EntityManager em = currentEntityManager();
|
||||||
|
|
||||||
|
String query = null;
|
||||||
|
List<CompUser> rs = null;
|
||||||
|
CompUser user = null;
|
||||||
|
|
||||||
|
// TODO: test when support for collection valued parameters is available
|
||||||
|
// Collection params = new ArrayList();
|
||||||
|
// params.add(FemaleUser.class);
|
||||||
|
// params.add(MaleUser.class);
|
||||||
|
// query = "SELECT e FROM CompUser e where TYPE(e) = :params";
|
||||||
|
// rs = em.createQuery(query).
|
||||||
|
// setParameter("params", params).getResultList();
|
||||||
|
// user = rs.get(0);
|
||||||
|
// assertEquals("the name is not shannon", "Shannon ", user.getName());
|
||||||
|
|
||||||
|
query = "SELECT TYPE(e) FROM MaleUser e where TYPE(e) = MaleUser";
|
||||||
|
rs = em.createQuery(query).getResultList();
|
||||||
|
Object type = rs.get(0);
|
||||||
|
assertEquals(type, MaleUser.class);
|
||||||
|
|
||||||
|
query = "SELECT TYPE(e) FROM CompUser e where TYPE(e) = ?1";
|
||||||
|
rs = em.createQuery(query).
|
||||||
|
setParameter(1, FemaleUser.class).getResultList();
|
||||||
|
type = rs.get(0);
|
||||||
|
assertEquals(type, FemaleUser.class);
|
||||||
|
|
||||||
|
query = "SELECT TYPE(e) FROM MaleUser e where TYPE(e) = ?1";
|
||||||
|
rs = em.createQuery(query).
|
||||||
|
setParameter(1, MaleUser.class).getResultList();
|
||||||
|
type = rs.get(0);
|
||||||
|
assertEquals(type, MaleUser.class);
|
||||||
|
|
||||||
|
query = "SELECT e, FemaleUser, a FROM Address a, FemaleUser e " +
|
||||||
|
" where e.address IS NOT NULL";
|
||||||
|
List<Object> rs2 = em.createQuery(query).getResultList();
|
||||||
|
type = ((Object[]) rs2.get(0))[1];
|
||||||
|
assertEquals(type, FemaleUser.class);
|
||||||
|
|
||||||
|
query = "SELECT e FROM CompUser e where TYPE(e) = :typeName";
|
||||||
|
rs = em.createQuery(query).
|
||||||
|
setParameter("typeName", FemaleUser.class).getResultList();
|
||||||
|
user = rs.get(0);
|
||||||
|
assertEquals("the name is not shannon", "Shannon ", user.getName());
|
||||||
|
|
||||||
|
query = "SELECT e FROM CompUser e where TYPE(e) = ?1";
|
||||||
|
rs = em.createQuery(query).
|
||||||
|
setParameter(1, FemaleUser.class).getResultList();
|
||||||
|
user = rs.get(0);
|
||||||
|
assertEquals("the name is not shannon", "Shannon ", user.getName());
|
||||||
|
|
||||||
|
query = "SELECT e FROM CompUser e where TYPE(e) in (?1)";
|
||||||
|
rs = em.createQuery(query).
|
||||||
|
setParameter(1, MaleUser.class).getResultList();
|
||||||
|
user = rs.get(0);
|
||||||
|
assertEquals(user.getName(), "Seetha");
|
||||||
|
|
||||||
|
query = "SELECT e FROM CompUser e where TYPE(e) in (?1, ?2)";
|
||||||
|
rs = em.createQuery(query).
|
||||||
|
setParameter(1, FemaleUser.class).setParameter(2, MaleUser.class).
|
||||||
|
getResultList();
|
||||||
|
user = rs.get(0);
|
||||||
|
assertEquals("the name is not shannon", "Shannon ", user.getName());
|
||||||
|
|
||||||
|
query = "select sum(e.age) FROM CompUser e GROUP BY e.age" +
|
||||||
|
" HAVING ABS(e.age) = :param";
|
||||||
|
Long sum = (Long) em.createQuery(query).
|
||||||
|
setParameter("param", new Double(36)).getSingleResult();
|
||||||
|
assertEquals(sum.intValue(), 72);
|
||||||
|
|
||||||
|
String[] queries = {
|
||||||
|
"SELECT e FROM CompUser e where TYPE(e) = MaleUser",
|
||||||
|
"SELECT e from CompUser e where TYPE(e) in (FemaleUser)",
|
||||||
|
"SELECT e from CompUser e where TYPE(e) not in (FemaleUser)",
|
||||||
|
"SELECT e from CompUser e where TYPE(e) in (MaleUser, FemaleUser)",
|
||||||
|
"SELECT TYPE(e) FROM CompUser e where TYPE(e) = MaleUser",
|
||||||
|
"SELECT TYPE(e) FROM CompUser e",
|
||||||
|
"SELECT TYPE(a.user) FROM Address a",
|
||||||
|
"SELECT MaleUser FROM CompUser e",
|
||||||
|
"SELECT MaleUser FROM Address a",
|
||||||
|
"SELECT " +
|
||||||
|
" CASE TYPE(e) WHEN FemaleUser THEN 'Female' " +
|
||||||
|
" ELSE 'Male' " +
|
||||||
|
" END " +
|
||||||
|
" FROM CompUser e",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < queries.length; i++) {
|
||||||
|
query = queries[i];
|
||||||
|
List<Object> rs1 = em.createQuery(query).getResultList();
|
||||||
|
Object obj = rs1.get(0);
|
||||||
|
obj.toString();
|
||||||
|
System.err.println(obj+" rs size="+rs1.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
endEm(em);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompUser createUser(String name, String cName, Address add, int age,
|
||||||
|
boolean isMale) {
|
||||||
|
CompUser user = null;
|
||||||
|
if (isMale) {
|
||||||
|
user = new MaleUser();
|
||||||
|
user.setName(name);
|
||||||
|
user.setComputerName(cName);
|
||||||
|
user.setAddress(add);
|
||||||
|
user.setAge(age);
|
||||||
|
} else {
|
||||||
|
user = new FemaleUser();
|
||||||
|
user.setName(name);
|
||||||
|
user.setComputerName(cName);
|
||||||
|
user.setAddress(add);
|
||||||
|
user.setAge(age);
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,11 +69,11 @@ public class TestJPQLScalarExpressions extends AbstractTestCase {
|
||||||
endEm(em);
|
endEm(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public void testCoalesceExpressions() {
|
public void testCoalesceExpressions() {
|
||||||
EntityManager em = currentEntityManager();
|
EntityManager em = currentEntityManager();
|
||||||
startTx(em);
|
startTx(em);
|
||||||
|
|
||||||
|
|
||||||
String query = "SELECT e.name, " +
|
String query = "SELECT e.name, " +
|
||||||
"COALESCE (e.address.country, 'Unknown')" +
|
"COALESCE (e.address.country, 'Unknown')" +
|
||||||
" FROM CompUser e";
|
" FROM CompUser e";
|
||||||
|
@ -86,6 +86,7 @@ public class TestJPQLScalarExpressions extends AbstractTestCase {
|
||||||
endEm(em);
|
endEm(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public void testNullIfExpressions() {
|
public void testNullIfExpressions() {
|
||||||
EntityManager em = currentEntityManager();
|
EntityManager em = currentEntityManager();
|
||||||
startTx(em);
|
startTx(em);
|
||||||
|
@ -103,6 +104,7 @@ public class TestJPQLScalarExpressions extends AbstractTestCase {
|
||||||
endEm(em);
|
endEm(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public void testSimpleCaseExpressions() {
|
public void testSimpleCaseExpressions() {
|
||||||
EntityManager em = currentEntityManager();
|
EntityManager em = currentEntityManager();
|
||||||
|
|
||||||
|
@ -129,15 +131,23 @@ public class TestJPQLScalarExpressions extends AbstractTestCase {
|
||||||
Object[] result2 = (Object[]) rs2.get(rs2.size()-1);
|
Object[] result2 = (Object[]) rs2.get(rs2.size()-1);
|
||||||
assertEquals("the name is not seetha", "Seetha", result2[0]);
|
assertEquals("the name is not seetha", "Seetha", result2[0]);
|
||||||
|
|
||||||
// TODO: needs entity-type-expression
|
|
||||||
String query3 = "SELECT e.name, " +
|
String query3 = "SELECT e.name, " +
|
||||||
" CASE TYPE(e) WHEN FemaleUser THEN 'Female' " +
|
" CASE TYPE(e) WHEN FemaleUser THEN 'Female' " +
|
||||||
" ELSE 'Male' " +
|
" ELSE 'Male' " +
|
||||||
" END " +
|
" END as result" +
|
||||||
" FROM CompUser e";
|
" FROM CompUser e";
|
||||||
|
List rs3 = em.createQuery(query3).getResultList();
|
||||||
|
Object[] result3 = (Object[]) rs3.get(rs3.size()-1);
|
||||||
|
assertEquals("the result is not female", "Female", result3[1]);
|
||||||
|
assertEquals("the name is not shade", "Shade", result3[0]);
|
||||||
|
result3 = (Object[]) rs3.get(0);
|
||||||
|
assertEquals("the result is not male", "Male", result3[1]);
|
||||||
|
assertEquals("the name is not seetha", "Seetha", result3[0]);
|
||||||
|
|
||||||
endEm(em);
|
endEm(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public void testGeneralCaseExpressions() {
|
public void testGeneralCaseExpressions() {
|
||||||
EntityManager em = currentEntityManager();
|
EntityManager em = currentEntityManager();
|
||||||
startTx(em);
|
startTx(em);
|
||||||
|
@ -154,7 +164,6 @@ public class TestJPQLScalarExpressions extends AbstractTestCase {
|
||||||
" FROM CompUser e ORDER BY cage";
|
" FROM CompUser e ORDER BY cage";
|
||||||
|
|
||||||
List rs = em.createQuery(query).getResultList();
|
List rs = em.createQuery(query).getResultList();
|
||||||
|
|
||||||
|
|
||||||
String update = "UPDATE CompUser e SET e.age = " +
|
String update = "UPDATE CompUser e SET e.age = " +
|
||||||
"CASE WHEN e.age > 30 THEN e.age - 1 " +
|
"CASE WHEN e.age > 30 THEN e.age - 1 " +
|
||||||
|
@ -169,6 +178,7 @@ public class TestJPQLScalarExpressions extends AbstractTestCase {
|
||||||
endEm(em);
|
endEm(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public void testMathFuncOrderByAlias() {
|
public void testMathFuncOrderByAlias() {
|
||||||
EntityManager em = currentEntityManager();
|
EntityManager em = currentEntityManager();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue