mirror of https://github.com/apache/openjpa.git
OPENJPA-805 JPQL iteration 1: add support for Case Expressions
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@725728 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2bb40626e6
commit
979a6e373c
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.io.Serializable;
|
||||||
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
||||||
import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
|
import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
|
||||||
import org.apache.openjpa.jdbc.sql.DBDictionary;
|
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.AggregateListener;
|
||||||
import org.apache.openjpa.kernel.exps.Arguments;
|
import org.apache.openjpa.kernel.exps.Arguments;
|
||||||
import org.apache.openjpa.kernel.exps.Expression;
|
import org.apache.openjpa.kernel.exps.Expression;
|
||||||
|
@ -400,4 +401,50 @@ public class JDBCExpressionFactory
|
||||||
return new GetMapValue((Val) map, (Val) arg,
|
return new GetMapValue((Val) map, (Val) arg,
|
||||||
"gmv" + _getMapValueAlias++);
|
"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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -407,4 +407,25 @@ public interface ExpressionFactory {
|
||||||
* Return the object id of the given value.
|
* Return the object id of the given value.
|
||||||
*/
|
*/
|
||||||
public Value getObjectId (Value val);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -745,6 +745,27 @@ public class JPQLExpressionBuilder
|
||||||
case JJTSCALAREXPRESSION:
|
case JJTSCALAREXPRESSION:
|
||||||
return eval(onlyChild(node));
|
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
|
case JJTWHERE: // top-level WHERE clause
|
||||||
return getExpression(onlyChild(node));
|
return getExpression(onlyChild(node));
|
||||||
|
|
||||||
|
@ -1439,6 +1460,48 @@ public class JPQLExpressionBuilder
|
||||||
return (Expression) exp;
|
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) {
|
private Value getValue(JPQLNode node) {
|
||||||
return getValue(node, VAR_PATH);
|
return getValue(node, VAR_PATH);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue