diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GeneralCaseExpression.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GeneralCaseExpression.java new file mode 100644 index 000000000..2841fb430 --- /dev/null +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/GeneralCaseExpression.java @@ -0,0 +1,193 @@ +/* + * 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.JavaSQLTypes; +import org.apache.openjpa.jdbc.sql.Joins; +import org.apache.openjpa.jdbc.sql.Raw; +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.kernel.Filters; +import org.apache.openjpa.kernel.exps.ExpressionVisitor; +import org.apache.openjpa.meta.ClassMetaData; + +/** + * General case expression. + * + * @author Catalina Wei + */ +public class GeneralCaseExpression + extends AbstractVal { + + private final Exp[] _exp; + private final Val _val; + private ClassMetaData _meta = null; + private Class _cast = null; + + /** + * Constructor. + */ + public GeneralCaseExpression(Exp[] exp, Val val) { + _exp = exp; + _val = val; + } + + public Exp[] getExp() { + return _exp; + } + + public Val getVal() { + return _val; + } + + public Class getType() { + if (_cast != null) + return _cast; + Class type = _val.getType(); + for (int i = 0; i < _exp.length; i++) + type = Filters.promote(type, + ((WhenCondition) _exp[i]).getVal().getType()); + if (type == Raw.class) + return String.class; + return type; + } + + public ExpState initialize(Select sel, ExpContext ctx, int flags) { + ExpState[] states = new ExpState[_exp.length+1]; + Joins joins = null; + int i = 0; + for (; i < _exp.length; i++) { + states[i] = _exp[i].initialize(sel, ctx, null); + if (joins == null) + joins = states[i].joins; + else + joins = sel.and(joins, states[i].joins); + } + states[i] = _val.initialize(sel, ctx, 0); + if (joins == null) + joins = states[i].joins; + else + joins = sel.and(joins, states[i].joins); + return new GeneralCaseExpState(joins, states); + } + + private static class GeneralCaseExpState + extends ExpState { + + public ExpState[] states; + + public GeneralCaseExpState(Joins joins, ExpState[] states) { + super(joins); + this.states = states; + } + } + + public void appendTo(Select sel, ExpContext ctx, ExpState state, + SQLBuffer buf, int index) { + GeneralCaseExpState cstate = (GeneralCaseExpState) state; + + buf.append(" CASE "); + int i = 0; + for (; i < _exp.length; i++) + _exp[i].appendTo(sel, ctx, cstate.states[i], buf); + + buf.append(" ELSE "); + _val.appendTo(sel, ctx, cstate.states[i], buf, 0); + + buf.append(" END "); + } + + public void selectColumns(Select sel, ExpContext ctx, ExpState state, + boolean pks) { + GeneralCaseExpState cstate = (GeneralCaseExpState) state; + int i = 0; + for (; i < _exp.length; i++) + _exp[i].selectColumns(sel, ctx, cstate.states[i], pks); + _val.selectColumns(sel, ctx, cstate.states[i], pks); + } + + public void acceptVisit(ExpressionVisitor visitor) { + visitor.enter(this); + for (int i = 0; i < _exp.length; i++) + _exp[i].acceptVisit(visitor); + _val.acceptVisit(visitor); + visitor.exit(this); + } + + public int getId() { + return Val.SIMPLECASE_VAL; + } + + public void calculateValue(Select sel, ExpContext ctx, ExpState state, + Val other, ExpState otherState) { + GeneralCaseExpState gstate = (GeneralCaseExpState) state; + for (int i = 0; i < _exp.length; i++) { + BinaryOpExpState bstate = (BinaryOpExpState) gstate.states[i]; + ((WhenCondition) _exp[i]).getVal().calculateValue(sel, ctx, + bstate.state2, null, null); + } + _val.calculateValue(sel, ctx, gstate.states[_exp.length], null, null); + } + + public void groupBy(Select sel, ExpContext ctx, ExpState state) { + sel.groupBy(newSQLBuffer(sel, ctx, state)); + } + + public int length(Select sel, ExpContext ctx, ExpState state) { + return 1; + } + + private SQLBuffer newSQLBuffer(Select sel, ExpContext ctx, ExpState state) { + calculateValue(sel, ctx, state, null, null); + SQLBuffer buf = new SQLBuffer(ctx.store.getDBDictionary()); + appendTo(sel, ctx, state, buf, 0); + return buf; + } + + public Object load(ExpContext ctx, ExpState state, Result res) + throws SQLException { + return Filters.convert(res.getObject(this, + JavaSQLTypes.JDBC_DEFAULT, null), getType()); + } + + public void orderBy(Select sel, ExpContext ctx, ExpState state, + boolean asc) { + sel.orderBy(newSQLBuffer(sel, ctx, state), asc, false, getSelectAs()); + } + + public void select(Select sel, ExpContext ctx, ExpState state, boolean pks){ + sel.select(newSQLBuffer(sel, ctx, state), this); + } + + public ClassMetaData getMetaData() { + return _meta; + } + + public void setImplicitType(Class type) { + _cast = type; + } + + public void setMetaData(ClassMetaData meta) { + _meta = meta; + } +} + diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java index d3f760a18..c7c32509b 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/JDBCExpressionFactory.java @@ -23,6 +23,7 @@ import java.io.Serializable; import org.apache.openjpa.jdbc.meta.ClassMapping; import org.apache.openjpa.jdbc.meta.JavaSQLTypes; import org.apache.openjpa.jdbc.sql.DBDictionary; +import org.apache.openjpa.jdbc.sql.Raw; import org.apache.openjpa.kernel.exps.AggregateListener; import org.apache.openjpa.kernel.exps.Arguments; import org.apache.openjpa.kernel.exps.Expression; @@ -400,4 +401,50 @@ public class JDBCExpressionFactory return new GetMapValue((Val) map, (Val) arg, "gmv" + _getMapValueAlias++); } + + public Value simpleCaseExpression(Value caseOperand, Expression[] exp, + Value val1) { + Exp[] exps = new Exp[exp.length]; + for (int i = 0; i < exp.length; i++) + exps[i] = (Exp) exp[i]; + if (val1 instanceof Lit) { + Lit val = (Lit) val1; + StringBuffer value = new StringBuffer(val.getValue().toString()); + if (val.getParseType() == Literal.TYPE_SQ_STRING) + value.insert(0, "'").append("'"); + val.setValue(new Raw(value.toString())); + } + return new SimpleCaseExpression((Val) caseOperand, exps, + (Val) val1); + } + + public Value generalCaseExpression(Expression[] exp, + Value val) { + Exp[] exps = new Exp[exp.length]; + for (int i = 0; i < exp.length; i++) + exps[i] = (Exp) exp[i]; + return new GeneralCaseExpression(exps, (Val) val); + } + + public Expression whenCondition(Expression exp, Value val) { + return new WhenCondition((Exp) exp, (Val) val); + } + + public Expression whenScalar(Value val1, Value val2) { + if (val1 instanceof Lit) { + Lit val = (Lit) val1; + StringBuffer value = new StringBuffer(val.getValue().toString()); + if (val.getParseType() == Literal.TYPE_SQ_STRING) + value.insert(0, "'").append("'"); + val.setValue(new Raw(value.toString())); + } + if (val2 instanceof Lit) { + Lit val = (Lit) val2; + StringBuffer value = new StringBuffer(val.getValue().toString()); + if (val.getParseType() == Literal.TYPE_SQ_STRING) + value.insert(0, "'").append("'"); + val.setValue(new Raw(value.toString())); + } + return new WhenScalar((Val) val1, (Val) val2); + } } diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SimpleCaseExpression.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SimpleCaseExpression.java new file mode 100644 index 000000000..82a233447 --- /dev/null +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SimpleCaseExpression.java @@ -0,0 +1,228 @@ +/* + * 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.JavaSQLTypes; +import org.apache.openjpa.jdbc.sql.DBDictionary; +import org.apache.openjpa.jdbc.sql.Joins; +import org.apache.openjpa.jdbc.sql.Raw; +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.kernel.Filters; +import org.apache.openjpa.kernel.exps.ExpressionVisitor; +import org.apache.openjpa.meta.ClassMetaData; + +/** + * Simple case expression. + * + * @author Catalina Wei + */ +public class SimpleCaseExpression + extends AbstractVal { + + private final Val _caseOperand; + private final Exp[] _exp; + private final Val _val; + private ClassMetaData _meta = null; + private Class _cast = null; + + /** + * Constructor. + */ + public SimpleCaseExpression(Val caseOperand, Exp[] exp, Val val) { + _caseOperand = caseOperand; + _exp = exp; + _val = val; + } + + public Val getCaseOperand() { + return _caseOperand; + } + + public Exp[] getExp() { + return _exp; + } + + public Val getVal() { + return _val; + } + + public Class getType() { + if (_cast != null) + return _cast; + Class type = _val.getType(); + for (int i = 0; i < _exp.length; i++) + type = Filters.promote(type, + ((WhenScalar) _exp[i]).getVal2().getType()); + if (type == Raw.class) + return String.class; + return type; + } + + public ExpState initialize(Select sel, ExpContext ctx, int flags) { + ExpState[] states = new ExpState[_exp.length+2]; + Joins joins = null; + + states[0] = _caseOperand.initialize(sel, ctx, 0); + if (joins == null) + joins = states[0].joins; + else + joins = sel.and(joins, states[0].joins); + for (int i = 0; i < _exp.length; i++) { + states[i+1] = _exp[i].initialize(sel, ctx, null); + if (joins == null) + joins = states[i+1].joins; + else + joins = sel.and(joins, states[i+1].joins); + } + states[_exp.length+1] = _val.initialize(sel, ctx, 0); + if (joins == null) + joins = states[_exp.length+1].joins; + else + joins = sel.and(joins, states[_exp.length+1].joins); + return new SimpleCaseExpState(joins, states); + } + + private static class SimpleCaseExpState + extends ExpState { + + public ExpState[] states; + + public SimpleCaseExpState(Joins joins, ExpState[] states) { + super(joins); + this.states = states; + } + } + + public void appendTo(Select sel, ExpContext ctx, ExpState state, + SQLBuffer buf, int index) { + SimpleCaseExpState cstate = (SimpleCaseExpState) state; + + DBDictionary dict = ctx.store.getDBDictionary(); + + buf.append(" CASE "); + + for (int i = 0; i < _exp.length; i++) { + // if back-end does not support simple case expression, + // pushdown sql as general case expression. + + if (!dict.supportsSimpleCaseExpression) + buf.append(" WHEN "); + + if (i == 0 || !dict.supportsSimpleCaseExpression) + _caseOperand.appendTo(sel, ctx, cstate.states[0], buf, 0); + + if (!dict.supportsSimpleCaseExpression) + buf.append(" = "); + else + buf.append(" WHEN "); + + _exp[i].appendTo(sel, ctx, cstate.states[i+1], buf); + } + buf.append(" ELSE "); + _val.appendTo(sel, ctx, cstate.states[_exp.length+1], buf, 0); + + buf.append(" END "); + } + + public void selectColumns(Select sel, ExpContext ctx, ExpState state, + boolean pks) { + SimpleCaseExpState cstate = (SimpleCaseExpState) state; + + _caseOperand.selectColumns(sel, ctx, cstate.states[0], pks); + for (int i = 0; i < _exp.length; i++) + _exp[i].selectColumns(sel, ctx, cstate.states[i+1], pks); + _val.selectColumns(sel, ctx, cstate.states[_exp.length+1], pks); + } + + public void acceptVisit(ExpressionVisitor visitor) { + visitor.enter(this); + _caseOperand.acceptVisit(visitor); + for (int i = 0; i < _exp.length; i++) + _exp[i].acceptVisit(visitor); + _val.acceptVisit(visitor); + visitor.exit(this); + } + + public int getId() { + return Val.SIMPLECASE_VAL; + } + + public void calculateValue(Select sel, ExpContext ctx, ExpState state, + Val other, ExpState otherState) { + SimpleCaseExpState cstate = (SimpleCaseExpState) state; + _caseOperand.calculateValue(sel, ctx, cstate.states[0], other, + otherState); + for (int i = 0; i < _exp.length; i++) { + BinaryOpExpState bstate = (BinaryOpExpState) cstate.states[i+1]; + ((WhenScalar) _exp[i]).getVal1().calculateValue(sel, ctx, + bstate.state1, null, null); + ((WhenScalar) _exp[i]).getVal2().calculateValue(sel, ctx, + bstate.state2, null, null); + } + _val.calculateValue(sel, ctx, cstate.states[_exp.length+1], other, + otherState); + } + + public void groupBy(Select sel, ExpContext ctx, ExpState state) { + sel.groupBy(newSQLBuffer(sel, ctx, state)); + } + + public int length(Select sel, ExpContext ctx, ExpState state) { + return 1; + } + + private SQLBuffer newSQLBuffer(Select sel, ExpContext ctx, ExpState state) { + calculateValue(sel, ctx, state, null, null); + SQLBuffer buf = new SQLBuffer(ctx.store.getDBDictionary()); + appendTo(sel, ctx, state, buf, 0); + return buf; + } + + public Object load(ExpContext ctx, ExpState state, Result res) + throws SQLException { + return Filters.convert(res.getObject(this, + JavaSQLTypes.JDBC_DEFAULT, null), getType()); + } + + public void orderBy(Select sel, ExpContext ctx, ExpState state, + boolean asc) { + sel.orderBy(newSQLBuffer(sel, ctx, state), asc, false, getSelectAs()); + } + + public void select(Select sel, ExpContext ctx, ExpState state, boolean pks){ + sel.select(newSQLBuffer(sel, ctx, state), this); + } + + public ClassMetaData getMetaData() { + return _meta; + } + + public void setImplicitType(Class type) { + _cast = type; + } + + public void setMetaData(ClassMetaData meta) { + _meta = meta; + } +} + diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/WhenCondition.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/WhenCondition.java new file mode 100644 index 000000000..cc3215248 --- /dev/null +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/WhenCondition.java @@ -0,0 +1,94 @@ +/* + * 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.util.Map; + +import org.apache.openjpa.jdbc.sql.SQLBuffer; +import org.apache.openjpa.jdbc.sql.Select; +import org.apache.openjpa.kernel.exps.ExpressionVisitor; + +/** + * Value produced by a when_clause of a case expression. + * + * @author Catalina Wei + */ +public class WhenCondition + implements Exp { + + private final Exp _exp; + private final Val _val; + + /** + * Constructor. + */ + public WhenCondition(Exp exp, Val val) { + _exp = exp; + _val = val; + } + + public Exp getExp() { + return _exp; + } + + public Val getVal() { + return _val; + } + + public Class getType() { + return _val.getType(); + } + + public ExpState initialize(Select sel, ExpContext ctx, Map contains) { + ExpState s1 = _exp.initialize(sel, ctx, contains); + ExpState s2 = _val.initialize(sel, ctx, 0); + return new BinaryOpExpState(sel.and(s1.joins, s2.joins), s1, s2); + } + + public void appendTo(Select sel, ExpContext ctx, ExpState state, + SQLBuffer buf) { + BinaryOpExpState bstate = (BinaryOpExpState) state; + + buf.append(" WHEN "); + + _exp.appendTo(sel, ctx, bstate.state1, buf); + buf.append(" THEN "); + _val.appendTo(sel, ctx, bstate.state2, buf, 0); + + } + + public void selectColumns(Select sel, ExpContext ctx, ExpState state, + boolean pks) { + BinaryOpExpState bstate = (BinaryOpExpState) state; + _exp.selectColumns(sel, ctx, bstate.state1, pks); + _val.selectColumns(sel, ctx, bstate.state2, pks); + } + + public void acceptVisit(ExpressionVisitor visitor) { + visitor.enter(this); + _exp.acceptVisit(visitor); + _val.acceptVisit(visitor); + visitor.exit(this); + } + + public int getId() { + return Val.WHENCONDITION_VAL; + } +} + diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/WhenScalar.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/WhenScalar.java new file mode 100644 index 000000000..4522de01e --- /dev/null +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/WhenScalar.java @@ -0,0 +1,90 @@ +/* + * 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.util.Map; + +import org.apache.openjpa.jdbc.sql.SQLBuffer; +import org.apache.openjpa.jdbc.sql.Select; +import org.apache.openjpa.kernel.exps.ExpressionVisitor; + +/** + * Value produced by a when_clause of a case expression. + * + * @author Catalina Wei + */ +public class WhenScalar + implements Exp { + + private final Val _val1; + private final Val _val2; + + /** + * Constructor. + */ + public WhenScalar(Val val1, Val val2) { + _val1 = val1; + _val2 = val2; + } + + public Val getVal1() { + return _val1; + } + + public Val getVal2() { + return _val2; + } + + public Class getType() { + return _val2.getType(); + } + + public ExpState initialize(Select sel, ExpContext ctx, Map contains) { + ExpState s1 = _val1.initialize(sel, ctx, 0); + ExpState s2 = _val2.initialize(sel, ctx, 0); + return new BinaryOpExpState(sel.and(s1.joins, s2.joins), s1, s2); + } + + public void appendTo(Select sel, ExpContext ctx, ExpState state, + SQLBuffer buf) { + BinaryOpExpState bstate = (BinaryOpExpState) state; + _val1.appendTo(sel, ctx, bstate.state1, buf, 0); + buf.append(" THEN "); + _val2.appendTo(sel, ctx, bstate.state2, buf, 0); + } + + public void selectColumns(Select sel, ExpContext ctx, ExpState state, + boolean pks) { + BinaryOpExpState bstate = (BinaryOpExpState) state; + _val1.selectColumns(sel, ctx, bstate.state1, pks); + _val2.selectColumns(sel, ctx, bstate.state2, pks); + } + + public void acceptVisit(ExpressionVisitor visitor) { + visitor.enter(this); + _val1.acceptVisit(visitor); + _val2.acceptVisit(visitor); + visitor.exit(this); + } + + public int getId() { + return Val.WHENSCALAR_VAL; + } +} + diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java index 580713877..19e6c8de8 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/ExpressionFactory.java @@ -407,4 +407,25 @@ public interface ExpressionFactory { * Return the object id of the given value. */ public Value getObjectId (Value val); + + /** + * Return a simple case expression + */ + public Value simpleCaseExpression(Value caseOperand, + Expression[] exp, Value val); + + /** + * Return a general case expression + */ + public Value generalCaseExpression(Expression[] exp, Value val); + + /** + * Return a when condidional clause + */ + public Expression whenCondition(Expression exp, Value val); + + /** + * Return a when scalar_expression clause + */ + public Expression whenScalar(Value val1, Value val2); } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java index 6ffdb5ed6..470a8fdf4 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/InMemoryExpressionFactory.java @@ -725,4 +725,24 @@ public class InMemoryExpressionFactory } } } + + public Value generalCaseExpression(Expression[] exp, Value val) { + // TODO Auto-generated method stub + return null; + } + + public Value simpleCaseExpression(Value caseOperand, Expression[] exp, Value val) { + // TODO Auto-generated method stub + return null; + } + + public Expression whenCondition(Expression exp, Value val) { + // TODO Auto-generated method stub + return null; + } + + public Expression whenScalar(Value val1, Value val2) { + // TODO Auto-generated method stub + return null; + } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java index 4a94a5748..00090bd76 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java @@ -745,6 +745,27 @@ public class JPQLExpressionBuilder case JJTSCALAREXPRESSION: return eval(onlyChild(node)); + case JJTTYPE: + return eval(onlyChild(node)); + + case JJTCLASSNAME: + return getPathOrConstant(node); + + case JJTCASE: + return eval(onlyChild(node)); + + case JJTSCASE: + return getSimpleCaseExpression(node); + + case JJTGCASE: + return getGeneralCaseExpression(node); + + case JJTWHEN: + return getWhenCondition(node); + + case JJTWHENSCALAR: + return getWhenScalar(node); + case JJTWHERE: // top-level WHERE clause return getExpression(onlyChild(node)); @@ -1439,6 +1460,48 @@ public class JPQLExpressionBuilder return (Expression) exp; } + /** + * Returns a Simple Case Expression for the given node by eval'ing it. + */ + private Value getSimpleCaseExpression(JPQLNode node) { + Object caseOperand = eval(node.getChild(0)); + int nChild = node.getChildCount(); + + Object val = eval(lastChild(node)); + Object exp[] = new Expression[nChild - 2]; + for (int i = 1; i < nChild - 1; i++) + exp[i-1] = eval(node.children[i]); + + return factory.simpleCaseExpression((Value) caseOperand, + (Expression[]) exp, (Value) val); + } + + /** + * Returns a General Case Expression for the given node by eval'ing it. + */ + private Value getGeneralCaseExpression(JPQLNode node) { + int nChild = node.getChildCount(); + + Object val = eval(lastChild(node)); + Object exp[] = new Expression[nChild - 1]; + for (int i = 0; i < nChild - 1; i++) + exp[i] = (Expression) eval(node.children[i]); + + return factory.generalCaseExpression((Expression[]) exp, (Value) val); + } + + private Expression getWhenCondition(JPQLNode node) { + Object exp = eval(firstChild(node)); + Object val = eval(secondChild(node)); + return factory.whenCondition((Expression) exp, (Value) val); + } + + private Expression getWhenScalar(JPQLNode node) { + Object val1 = eval(firstChild(node)); + Object val2 = eval(secondChild(node)); + return factory.whenScalar((Value) val1, (Value) val2); + } + private Value getValue(JPQLNode node) { return getValue(node, VAR_PATH); } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/expressions/TestJPQLScalarExpressions.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/expressions/TestJPQLScalarExpressions.java new file mode 100644 index 000000000..2a088a78b --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jpql/expressions/TestJPQLScalarExpressions.java @@ -0,0 +1,169 @@ +/* + * 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.List; +import javax.persistence.EntityManager; + +import org.apache.openjpa.persistence.common.apps.*; +import org.apache.openjpa.persistence.common.utils.AbstractTestCase; + +public class TestJPQLScalarExpressions extends AbstractTestCase { + + private int userid1, userid2, userid3, userid4, userid5, userid6; + + public TestJPQLScalarExpressions(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); + } + + public void testSimpleCaseExpressions() { + EntityManager em = currentEntityManager(); + + CompUser user = em.find(CompUser.class, userid1); + assertNotNull("user is null", user); + assertEquals("the name is not seetha", "Seetha", user.getName()); + String query = "SELECT e.name, e.age+1 as cage, " + + "CASE e.address.country WHEN 'USA'" + + " THEN 'us' " + + " ELSE 'non-us' END as d2," + + " e.address.country " + + " FROM CompUser e ORDER BY cage, d2 DESC"; + List rs = em.createQuery(query).getResultList(); + Object[] result = (Object[]) rs.get(rs.size()-1); + assertEquals("the name is not seetha", "Seetha", result[0]); + + String query2 = "SELECT e.name, e.age+1 as cage, " + + "CASE e.address.country WHEN 'USA'" + + " THEN 'United-States' " + + " ELSE e.address.country END as d2," + + " e.address.country " + + " FROM CompUser e ORDER BY cage, d2 DESC"; + List rs2 = em.createQuery(query2).getResultList(); + 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 " + + " FROM CompUser e"; + endEm(em); + } + + public void testGeneralCaseExpressions() { + EntityManager em = currentEntityManager(); + startTx(em); + + CompUser user = em.find(CompUser.class, userid1); + assertNotNull("user is null", user); + assertEquals("the name is not seetha", "Seetha", user.getName()); + + String query = "SELECT e.name, e.age, " + + " CASE WHEN e.age > 30 THEN e.age - 1 " + + " WHEN e.age < 15 THEN e.age + 1 " + + " ELSE e.age + 0 " + + " END AS cage " + + " FROM CompUser e ORDER BY cage"; + + 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 " + + "ELSE e.age + 0 " + + "END"; + + int result = em.createQuery(update).executeUpdate(); + + assertEquals("the result is not 6", 6, result); + endTx(em); + endEm(em); + } + + public void testMathFuncOrderByAlias() { + EntityManager em = currentEntityManager(); + + String query = "SELECT e.age * 2 as cAge FROM CompUser e ORDER BY cAge"; + + List result = em.createQuery(query).getResultList(); + + assertNotNull(result); + assertEquals(6, result.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; + } +}