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");
|
||||
}
|
||||
|
||||
public void appendType(Select sel, ExpContext ctx, ExpState state,
|
||||
SQLBuffer sql) {
|
||||
sql.append("1");
|
||||
}
|
||||
|
||||
public void appendSize(Select sel, ExpContext ctx, ExpState state,
|
||||
SQLBuffer sql) {
|
||||
sql.append("1");
|
||||
|
|
|
@ -91,7 +91,11 @@ class InExpression
|
|||
public void appendTo(Select sel, ExpContext ctx, ExpState state,
|
||||
SQLBuffer buf) {
|
||||
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);
|
||||
|
||||
List list = null;
|
||||
|
|
|
@ -247,6 +247,10 @@ public class JDBCExpressionFactory
|
|||
return new Lit(val, ptype);
|
||||
}
|
||||
|
||||
public Literal newTypeLiteral(Object val, int ptype) {
|
||||
return new TypeLit(val, ptype);
|
||||
}
|
||||
|
||||
public Value getThis() {
|
||||
return new PCPath(_type);
|
||||
}
|
||||
|
@ -396,6 +400,10 @@ public class JDBCExpressionFactory
|
|||
return new Index((Val) val);
|
||||
}
|
||||
|
||||
public Value type(Value val) {
|
||||
return new Type((Val) val);
|
||||
}
|
||||
|
||||
public Value getObjectId(Value val) {
|
||||
if (val instanceof Const)
|
||||
return new ConstGetObjectId((Const) val);
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.ListIterator;
|
|||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
|
||||
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.ValueMapping;
|
||||
import org.apache.openjpa.jdbc.schema.Column;
|
||||
|
@ -814,6 +815,33 @@ public class PCPath
|
|||
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,
|
||||
SQLBuffer sql) {
|
||||
PathExpState pstate = (PathExpState) state;
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Collection;
|
|||
import java.util.Map;
|
||||
|
||||
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;
|
||||
|
@ -82,6 +83,12 @@ public class Param
|
|||
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) {
|
||||
return ((ParamExpState) state).sqlValue;
|
||||
}
|
||||
|
@ -98,6 +105,9 @@ public class Param
|
|||
|
||||
public Object sqlValue = null;
|
||||
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,
|
||||
|
@ -108,6 +118,14 @@ public class Param
|
|||
if (other != null && !_container) {
|
||||
pstate.sqlValue = other.toDataStoreValue(sel, ctx, otherState, val);
|
||||
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)) {
|
||||
ClassMapping mapping = ctx.store.getConfiguration().
|
||||
getMappingRepositoryInstance().getMapping(val.getClass(),
|
||||
|
@ -125,6 +143,10 @@ public class Param
|
|||
if (pstate.otherLength > 1)
|
||||
sql.appendValue(((Object[]) pstate.sqlValue)[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
|
||||
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,
|
||||
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.
|
||||
*/
|
||||
|
|
|
@ -862,6 +862,10 @@ public class FieldMapping
|
|||
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) {
|
||||
return assertStrategy().join(joins, forceOuter);
|
||||
}
|
||||
|
|
|
@ -185,6 +185,11 @@ public interface FieldStrategy
|
|||
*/
|
||||
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.
|
||||
*/
|
||||
|
|
|
@ -139,6 +139,10 @@ public abstract class AbstractFieldStrategy
|
|||
sql.append("1");
|
||||
}
|
||||
|
||||
public void appendType(SQLBuffer sql, Select sel, Joins joins) {
|
||||
sql.append("1");
|
||||
}
|
||||
|
||||
public Joins join(Joins joins, boolean forceOuter) {
|
||||
return joins;
|
||||
}
|
||||
|
|
|
@ -402,6 +402,13 @@ public interface ExpressionFactory {
|
|||
*/
|
||||
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
|
||||
* within aggregates, for example: max(distinct(path))
|
||||
|
@ -445,4 +452,10 @@ public interface ExpressionFactory {
|
|||
* Return a nullif expression
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
public Literal newTypeLiteral(Object val, int parseType) {
|
||||
return new TypeLit(val, parseType);
|
||||
}
|
||||
|
||||
public Value getThis() {
|
||||
return new This();
|
||||
}
|
||||
|
@ -635,6 +639,10 @@ public class InMemoryExpressionFactory
|
|||
return new Index((Val) val);
|
||||
}
|
||||
|
||||
public Value type(Value val) {
|
||||
return new Type((Val) val);
|
||||
}
|
||||
|
||||
public Value getObjectId(Value 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_STRING = 3;
|
||||
public static final int TYPE_SQ_STRING = 4; // single-quoted string
|
||||
public static final int TYPE_CLASS = 5;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
proj.setAlias(alias);
|
||||
exps.projections[i] = proj;
|
||||
exps.projectionClauses[i] = aliasNode == null ?
|
||||
assemble(node.id == JJTSCALAREXPRESSION ? firstChild(node)
|
||||
: node) : alias;
|
||||
exps.projectionClauses[i] = aliasNode != null ? alias :
|
||||
projectionClause(node.id == JJTSCALAREXPRESSION ?
|
||||
firstChild(node) : node);
|
||||
exps.projectionAliases[i] = alias;
|
||||
}
|
||||
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) {
|
||||
// determine whether we want to select, delete, or update
|
||||
if (root().id == JJTSELECT || root().id == JJTSUBSELECT)
|
||||
|
@ -746,7 +755,10 @@ public class JPQLExpressionBuilder
|
|||
return eval(onlyChild(node));
|
||||
|
||||
case JJTTYPE:
|
||||
return eval(onlyChild(node));
|
||||
return getType(onlyChild(node));
|
||||
|
||||
case JJTTYPELITERAL:
|
||||
return getTypeLiteral(node);
|
||||
|
||||
case JJTCLASSNAME:
|
||||
return getPathOrConstant(node);
|
||||
|
@ -754,10 +766,10 @@ public class JPQLExpressionBuilder
|
|||
case JJTCASE:
|
||||
return eval(onlyChild(node));
|
||||
|
||||
case JJTSCASE:
|
||||
case JJTSIMPLECASE:
|
||||
return getSimpleCaseExpression(node);
|
||||
|
||||
case JJTGCASE:
|
||||
case JJTGENERALCASE:
|
||||
return getGeneralCaseExpression(node);
|
||||
|
||||
case JJTWHEN:
|
||||
|
@ -814,6 +826,10 @@ public class JPQLExpressionBuilder
|
|||
case JJTPOSITIONALINPUTPARAMETER:
|
||||
return getParameter(node.text, true);
|
||||
|
||||
case JJTCOLLECTIONPARAMETER:
|
||||
// TODO: support collection valued parameters
|
||||
return getParameter(onlyChild(node).text, true);
|
||||
|
||||
case JJTOR: // x OR y
|
||||
return factory.or(getExpression(left(node)),
|
||||
getExpression(right(node)));
|
||||
|
@ -892,14 +908,19 @@ public class JPQLExpressionBuilder
|
|||
factory.lessThanEqual(val1, val3)));
|
||||
|
||||
case JJTIN: // x.field [NOT] IN ('a', 'b', 'c')
|
||||
|
||||
// TYPE(x...) [NOT] IN (entityTypeLiteral1,...)
|
||||
Expression inExp = null;
|
||||
Iterator inIterator = node.iterator();
|
||||
// the first child is the path
|
||||
val1 = getValue((JPQLNode) inIterator.next());
|
||||
JPQLNode first = (JPQLNode) inIterator.next();
|
||||
val1 = getValue(first);
|
||||
|
||||
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
|
||||
// <value> IN (<single value>)
|
||||
|
@ -1360,6 +1381,21 @@ public class JPQLExpressionBuilder
|
|||
} else if (val instanceof Path) {
|
||||
return (Path) val;
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
@ -1367,6 +1403,24 @@ public class JPQLExpressionBuilder
|
|||
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) {
|
||||
// first check to see if the path is an enum or static field, and
|
||||
// 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) {
|
||||
return getPath(node, false, true);
|
||||
}
|
||||
|
|
|
@ -745,19 +745,26 @@ void between_expression() #BETWEEN : { }
|
|||
|
||||
void in_expression() #IN : { }
|
||||
{
|
||||
(path() | scalar_function()) [ LOOKAHEAD(1) <NOT> { jjtThis.not = true; }] <IN>
|
||||
"(" (literal_or_param()
|
||||
(path() | scalar_function() | type_discriminator()) [ LOOKAHEAD(1) <NOT> { jjtThis.not = true; }] <IN>
|
||||
("(" (literal_or_param()
|
||||
(<COMMA> (literal_or_param()))* | subquery())
|
||||
")"
|
||||
")"
|
||||
| collection_valued_input_parameter()
|
||||
)
|
||||
}
|
||||
|
||||
void entity_type_literal() #TYPELITERAL : { }
|
||||
{
|
||||
identification_variable()
|
||||
}
|
||||
|
||||
void literal_or_param() : { }
|
||||
{
|
||||
(numeric_literal()
|
||||
| string_literal()
|
||||
| boolean_literal()
|
||||
| input_parameter())
|
||||
| input_parameter()
|
||||
| entity_type_literal())
|
||||
}
|
||||
|
||||
|
||||
|
@ -941,46 +948,51 @@ void arithmetic_factor() : { }
|
|||
LOOKAHEAD(2) "(" arithmetic_expression() ")" |
|
||||
functions_returning_numerics() |
|
||||
aggregate_select_expression() |
|
||||
LOOKAHEAD(case_expression()) case_expression() |
|
||||
subquery()
|
||||
}
|
||||
|
||||
|
||||
void qualified_path() #QPATH : { }
|
||||
void qualified_path() #QUALIFIEDPATH : { }
|
||||
{
|
||||
general_identification_variable() (LOOKAHEAD(2) <DOT> path_component())+
|
||||
}
|
||||
|
||||
void qualified_identification_variable() #QIDENTIFIER : { }
|
||||
void qualified_identification_variable() #QUALIFIEDIDENTIFIER : { }
|
||||
{
|
||||
( <KEY> "(" identification_variable() ")" #KEY
|
||||
| <VALUE> "(" identification_variable() ")" #VALUE
|
||||
| <ENTRY> "(" identification_variable() ")" #ENTRY
|
||||
( <KEY> "(" identification_variable() ")" #KEY(1)
|
||||
| <VALUE> "(" identification_variable() ")" #VALUE(1)
|
||||
| <ENTRY> "(" identification_variable() ")" #ENTRY(1)
|
||||
)
|
||||
}
|
||||
|
||||
void general_identification_variable() #GIDENTIFIER : { }
|
||||
void general_identification_variable() #GENERALIDENTIFIER : { }
|
||||
{
|
||||
( <KEY> "(" identification_variable() ")" #KEY
|
||||
| <VALUE> "(" identification_variable() ")" #VALUE
|
||||
( <KEY> "(" identification_variable() ")" #KEY(1)
|
||||
| <VALUE> "(" identification_variable() ")" #VALUE(1)
|
||||
)
|
||||
}
|
||||
|
||||
void entity_type_comp() : { }
|
||||
{
|
||||
entity_type_expression()
|
||||
( <EQ> entity_type_expression() #EQUALS(2)
|
||||
| <NE> entity_type_expression() #NOTEQUALS(2)
|
||||
(entity_type_expression() | entity_type_literal())
|
||||
( <EQ> (entity_type_expression() | entity_type_literal()) #EQUALS(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()
|
||||
| LOOKAHEAD(path()) path()
|
||||
<TYPE> "(" (LOOKAHEAD(path()) path()
|
||||
| LOOKAHEAD(general_identification_variable()) general_identification_variable()
|
||||
| LOOKAHEAD(identification_variable()) identification_variable()
|
||||
| LOOKAHEAD(input_parameter()) input_parameter())
|
||||
")" |
|
||||
classname() #TYPE_LITERAL |
|
||||
")"
|
||||
}
|
||||
|
||||
void entity_type_expression(): { }
|
||||
{
|
||||
type_discriminator() |
|
||||
input_parameter()
|
||||
}
|
||||
|
||||
|
@ -990,7 +1002,7 @@ void scalar_expression() #SCALAREXPRESSION : { }
|
|||
LOOKAHEAD(case_expression()) case_expression() |
|
||||
LOOKAHEAD(string_primary()) string_primary() |
|
||||
LOOKAHEAD(datetime_primary()) datetime_primary() |
|
||||
LOOKAHEAD(enum_primary()) enum_primary()
|
||||
LOOKAHEAD(enum_primary()) enum_primary() |
|
||||
LOOKAHEAD(entity_type_expression()) entity_type_expression()
|
||||
}
|
||||
|
||||
|
@ -1004,29 +1016,31 @@ void case_expression() #CASE : { }
|
|||
<NULLIF> nullif_expression()
|
||||
}
|
||||
|
||||
void general_case_expression() #GCASE : { }
|
||||
void general_case_expression() #GENERALCASE : { }
|
||||
{
|
||||
(when_clause())+
|
||||
<ELSE> scalar_expression()
|
||||
<ELSE> (LOOKAHEAD(2) scalar_expression() | entity_type_literal())
|
||||
<END>
|
||||
}
|
||||
|
||||
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())+
|
||||
<ELSE> scalar_expression()
|
||||
<ELSE> (LOOKAHEAD(2) scalar_expression() | entity_type_literal())
|
||||
<END>
|
||||
}
|
||||
|
||||
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 : { }
|
||||
|
@ -1409,6 +1423,12 @@ void input_parameter() : { }
|
|||
}
|
||||
|
||||
|
||||
void collection_valued_input_parameter() #COLLECTIONPARAMETER: { }
|
||||
{
|
||||
named_input_parameter() | positional_input_parameter()
|
||||
}
|
||||
|
||||
|
||||
void named_input_parameter() #NAMEDINPUTPARAMETER :
|
||||
{ Token t; }
|
||||
{
|
||||
|
|
|
@ -72,3 +72,4 @@ query-extensions-error: This JPQL query uses non-standard OpenJPA \
|
|||
JPQL extensions.
|
||||
jpql-parse-error: "{1}" while parsing JPQL "{0}". See nested stack trace for \
|
||||
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);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testCoalesceExpressions() {
|
||||
EntityManager em = currentEntityManager();
|
||||
startTx(em);
|
||||
|
||||
|
||||
String query = "SELECT e.name, " +
|
||||
"COALESCE (e.address.country, 'Unknown')" +
|
||||
" FROM CompUser e";
|
||||
|
@ -86,6 +86,7 @@ public class TestJPQLScalarExpressions extends AbstractTestCase {
|
|||
endEm(em);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testNullIfExpressions() {
|
||||
EntityManager em = currentEntityManager();
|
||||
startTx(em);
|
||||
|
@ -103,6 +104,7 @@ public class TestJPQLScalarExpressions extends AbstractTestCase {
|
|||
endEm(em);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testSimpleCaseExpressions() {
|
||||
EntityManager em = currentEntityManager();
|
||||
|
||||
|
@ -129,15 +131,23 @@ public class TestJPQLScalarExpressions extends AbstractTestCase {
|
|||
Object[] result2 = (Object[]) rs2.get(rs2.size()-1);
|
||||
assertEquals("the name is not seetha", "Seetha", result2[0]);
|
||||
|
||||
// TODO: needs entity-type-expression
|
||||
String query3 = "SELECT e.name, " +
|
||||
" CASE TYPE(e) WHEN FemaleUser THEN 'Female' " +
|
||||
" ELSE 'Male' " +
|
||||
" END " +
|
||||
" END as result" +
|
||||
" 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);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testGeneralCaseExpressions() {
|
||||
EntityManager em = currentEntityManager();
|
||||
startTx(em);
|
||||
|
@ -155,7 +165,6 @@ public class TestJPQLScalarExpressions extends AbstractTestCase {
|
|||
|
||||
List rs = em.createQuery(query).getResultList();
|
||||
|
||||
|
||||
String update = "UPDATE CompUser e SET e.age = " +
|
||||
"CASE WHEN e.age > 30 THEN e.age - 1 " +
|
||||
"WHEN e.age < 15 THEN e.age + 1 " +
|
||||
|
@ -169,6 +178,7 @@ public class TestJPQLScalarExpressions extends AbstractTestCase {
|
|||
endEm(em);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testMathFuncOrderByAlias() {
|
||||
EntityManager em = currentEntityManager();
|
||||
|
||||
|
|
Loading…
Reference in New Issue