OPENJPA-488, OPENJPA-489, OPENJPA-490, OPENJPA-491, OPENJPA-492

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@612345 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Patrick Linskey 2008-01-16 03:49:23 +00:00
parent 72f7d7ce43
commit 8c4cf9511e
14 changed files with 537 additions and 111 deletions

View File

@ -26,6 +26,8 @@ import org.apache.openjpa.jdbc.kernel.exps.FilterValue;
public abstract class AbstractDB2Dictionary
extends DBDictionary {
public int varcharCastLength = 1000;
public AbstractDB2Dictionary() {
numericTypeName = "DOUBLE";
bitTypeName = "SMALLINT";
@ -36,11 +38,13 @@ public abstract class AbstractDB2Dictionary
// DB2-based databases have restrictions on having uncast parameters
// in string functions
toUpperCaseFunction = "UPPER(CAST({0} AS VARCHAR(1000)))";
toLowerCaseFunction = "LOWER(CAST({0} AS VARCHAR(1000)))";
toUpperCaseFunction = "UPPER(CAST({0} AS VARCHAR(" + varcharCastLength
+ ")))";
toLowerCaseFunction = "LOWER(CAST({0} AS VARCHAR(" + varcharCastLength
+ ")))";
stringLengthFunction = "LENGTH({0})";
concatenateFunction = "(CAST({0} AS VARCHAR(1000)))||"
+ "(CAST({1} AS VARCHAR(1000)))";
concatenateFunction = "(CAST({0} AS VARCHAR(" + varcharCastLength
+ ")))||(CAST({1} AS VARCHAR(1000)))";
trimLeadingFunction = "LTRIM({0})";
trimTrailingFunction = "RTRIM({0})";
@ -74,9 +78,11 @@ public abstract class AbstractDB2Dictionary
FilterValue start) {
buf.append("(LOCATE(CAST((");
find.appendTo(buf);
buf.append(") AS VARCHAR(1000)), CAST((");
buf.append(") AS VARCHAR(").append(Integer.toString(varcharCastLength))
.append(")), CAST((");
str.appendTo(buf);
buf.append(") AS VARCHAR(1000))");
buf.append(") AS VARCHAR(").append(Integer.toString(varcharCastLength))
.append("))");
if (start != null) {
buf.append(", CAST((");
start.appendTo(buf);
@ -89,15 +95,30 @@ public abstract class AbstractDB2Dictionary
FilterValue end) {
buf.append("SUBSTR(CAST((");
str.appendTo(buf);
buf.append(") AS VARCHAR(1000)), CAST((");
start.appendTo(buf);
buf.append(") AS INTEGER) + 1");
if (end != null) {
buf.append(", CAST((");
end.appendTo(buf);
buf.append(") AS INTEGER) - CAST((");
buf.append(") AS VARCHAR(").append(Integer.toString(varcharCastLength))
.append(")), ");
if (start.getValue() instanceof Number) {
long startLong = toLong(start);
buf.append(Long.toString(startLong + 1));
} else {
buf.append("CAST((");
start.appendTo(buf);
buf.append(") AS INTEGER)");
buf.append(") AS INTEGER) + 1");
}
if (end != null) {
buf.append(", ");
if (start.getValue() instanceof Number
&& end.getValue() instanceof Number) {
long startLong = toLong(start);
long endLong = toLong(end);
buf.append(Long.toString(endLong - startLong));
} else {
buf.append("CAST((");
end.appendTo(buf);
buf.append(") AS INTEGER) - CAST((");
start.appendTo(buf);
buf.append(") AS INTEGER)");
}
}
buf.append(")");
}

View File

@ -117,23 +117,23 @@ public abstract class AbstractSQLServerDictionary
public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
FilterValue end) {
buf.append("SUBSTRING(");
str.appendTo(buf);
buf.append(", ");
start.appendTo(buf);
buf.append(" + 1, ");
if (end != null) {
buf.append("(");
end.appendTo(buf);
buf.append(")");
} else {
if (end != null)
super.substring(buf, str, start, end);
else {
// ### it would be good to change this logic as in DBDictionary to
// ### simplify the generated SQL
buf.append("SUBSTRING(");
str.appendTo(buf);
buf.append(", ");
start.appendTo(buf);
buf.append(" + 1, ");
buf.append("LEN(");
str.appendTo(buf);
buf.append(")");
buf.append(" - (");
start.appendTo(buf);
buf.append("))");
}
buf.append(" - (");
start.appendTo(buf);
buf.append("))");
}
public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find,

View File

@ -63,6 +63,8 @@ public class AccessDictionary
supportsForeignKeys = false;
supportsDeferredConstraints = false;
maxIndexesPerTable = 32;
substringFunctionName = "MID";
}
public void setLong(PreparedStatement stmnt, int idx, long val, Column col)
@ -75,22 +77,5 @@ public class AccessDictionary
else
stmnt.setDouble(idx, val);
}
public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
FilterValue end) {
buf.append("MID(");
str.appendTo(buf);
buf.append(", (");
start.appendTo(buf);
buf.append(" + 1)");
if (end != null) {
buf.append(", (");
end.appendTo(buf);
buf.append(" - ");
start.appendTo(buf);
buf.append(")");
}
buf.append(")");
}
}

View File

@ -86,6 +86,7 @@ import org.apache.openjpa.jdbc.schema.Table;
import org.apache.openjpa.jdbc.schema.Unique;
import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.exps.Path;
import org.apache.openjpa.kernel.exps.Literal;
import org.apache.openjpa.lib.conf.Configurable;
import org.apache.openjpa.lib.conf.Configuration;
import org.apache.openjpa.lib.jdbc.ConnectionDecorator;
@ -2494,21 +2495,38 @@ public class DBDictionary
*/
public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
FilterValue end) {
buf.append(substringFunctionName).append("((");
buf.append(substringFunctionName).append("(");
str.appendTo(buf);
buf.append("), (");
start.appendTo(buf);
buf.append(" + 1)");
if (end != null) {
buf.append(", (");
end.appendTo(buf);
buf.append(" - (");
buf.append(", ");
if (start instanceof Number) {
long startLong = toLong(start);
buf.append(Long.toString(startLong + 1));
} else {
buf.append("(");
start.appendTo(buf);
buf.append("))");
buf.append(" + 1)");
}
if (end != null) {
buf.append(", ");
if (start.getValue() instanceof Number
&& end.getValue() instanceof Number) {
long startLong = toLong(start);
long endLong = toLong(end);
buf.append(Long.toString(endLong - startLong));
} else {
end.appendTo(buf);
buf.append(" - (");
start.appendTo(buf);
buf.append(")");
}
}
buf.append(")");
}
long toLong(FilterValue litValue) {
return ((Number) litValue.getValue()).longValue();
}
/**
* Invoke this database's indexOf function.
*

View File

@ -193,23 +193,6 @@ public class H2Dictionary extends DBDictionary {
buf.append(" OFFSET ").appendValue(start);
}
public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
FilterValue end) {
buf.append("SUBSTR(");
str.appendTo(buf);
buf.append(", (");
start.appendTo(buf);
buf.append(" + 1)");
if (end != null) {
buf.append(", (");
end.appendTo(buf);
buf.append(" - ");
start.appendTo(buf);
buf.append(")");
}
buf.append(")");
}
public void indexOf(SQLBuffer buf, FilterValue str, FilterValue find,
FilterValue start) {
buf.append("(POSITION(");

View File

@ -157,6 +157,8 @@ public class OracleDictionary
"LONG", "MAXEXTENTS", "MINUS", "MODE", "NOAUDIT", "NOCOMPRESS",
"NOWAIT", "OFFLINE", "ONLINE", "PCTFREE", "ROW",
}));
substringFunctionName = "SUBSTR";
}
public void endConfiguration() {
@ -427,23 +429,6 @@ public class OracleDictionary
return select;
}
public void substring(SQLBuffer buf, FilterValue str, FilterValue start,
FilterValue end) {
buf.append("SUBSTR(");
str.appendTo(buf);
buf.append(", (");
start.appendTo(buf);
buf.append(" + 1)");
if (end != null) {
buf.append(", (");
end.appendTo(buf);
buf.append(" - ");
start.appendTo(buf);
buf.append(")");
}
buf.append(")");
}
public void setString(PreparedStatement stmnt, int idx, String val,
Column col)
throws SQLException {

View File

@ -334,7 +334,8 @@ public interface ExpressionFactory {
/**
* Return a value representing the {@link String#substring} function on
* the given target with the given args.
* the given target with the given args. As with {@link String#substring},
* the start index is zero-based, and the second argument is the end index.
*/
public Value substring(Value str, Value args);

View File

@ -977,21 +977,28 @@ public class JPQLExpressionBuilder
// arg2 is the end index): we perform the translation by
// adding one to the first argument, and then adding the
// first argument to the second argument to get the endIndex
//
// ### we could get rid of some messy expressions by checking for
// the common case where the arguments are specified as
// a literal, in which case we could just do the calculations
// in memory; otherwise we wind up with ugly looking SQL like:
// SELECT ... FROM ... t1
// (SUBSTRING(t1.ASTR, (? - ?) + 1, (? + (? - ?)) - ((? - ?))) = ?)
// [params=(long) 2, (int) 1, (long) 2, (long) 2, (int) 1,
// (long) 2, (int) 1, (String) oo
return factory.substring(val1, factory.newArgumentList
(factory.subtract(val2, factory.newLiteral
(Numbers.valueOf(1), Literal.TYPE_NUMBER)),
(factory.add(val3,
(factory.subtract(val2, factory.newLiteral
(Numbers.valueOf(1), Literal.TYPE_NUMBER)))))));
Value start;
Value end;
if (val2 instanceof Literal && val3 instanceof Literal) {
// optimize SQL for the common case of two literals
long jpqlStart = ((Number) ((Literal) val2).getValue())
.longValue();
long length = ((Number) ((Literal) val3).getValue())
.longValue();
start = factory.newLiteral(new Long(jpqlStart - 1),
Literal.TYPE_NUMBER);
long endIndex = length + (jpqlStart - 1);
end = factory.newLiteral(new Long(endIndex),
Literal.TYPE_NUMBER);
} else {
start = factory.subtract(val2, factory.newLiteral
(Numbers.valueOf(1), Literal.TYPE_NUMBER));
end = factory.add(val3,
(factory.subtract(val2, factory.newLiteral
(Numbers.valueOf(1), Literal.TYPE_NUMBER))));
}
return factory.substring(val1, factory.newArgumentList(
start, end));
case JJTLOCATE:
// as with SUBSTRING (above), the semantics for LOCATE differ
@ -1067,6 +1074,15 @@ public class JPQLExpressionBuilder
case JJTCURRENTTIMESTAMP:
return factory.getCurrentTimestamp();
case JJTSELECTEXTENSION:
return eval(node.children[0]);
case JJTGROUPBYEXTENSION:
return eval(node.children[0]);
case JJTORDERBYEXTENSION:
return eval(node.children[0]);
default:
throw parseException(EX_FATAL, "bad-tree",
new Object[]{ node }, null);
@ -1669,9 +1685,6 @@ public class JPQLExpressionBuilder
// parser may sometimes (unfortunately) throw
throw new UserException(_loc.get("parse-error",
new Object[]{ e.toString(), jpql }));
} catch (ParseException e) {
throw new UserException(_loc.get("parse-error",
new Object[]{ e.toString(), jpql }), e);
}
}

View File

@ -64,6 +64,7 @@ import java.io.*;
public class JPQL
{
String jpql;
boolean extensionsEnabled = true;
public JPQL (String jpql)
@ -498,6 +499,13 @@ void select_expression() #SELECTEXPRESSION : { }
| identification_variable()
| (<OBJECT> "(" identification_variable() ")")
| constructor_expression()
| select_extension()
}
void select_extension() #SELECTEXTENSION(extensionsEnabled) : { }
{
scalar_function()
}
@ -506,12 +514,12 @@ void subselect_expressions() #SELECTEXPRESSIONS : { }
subselect_expression() (<COMMA> subselect_expression())*
}
void subselect_expression() #SELECTEXPRESSION : { }
{
LOOKAHEAD(path()) path()
| aggregate_select_expression()
| LOOKAHEAD(1) identification_variable()
}
@ -615,7 +623,13 @@ void groupby_clause() #GROUPBY : { }
void groupby_item() : { }
{
LOOKAHEAD(path()) path() | identification_variable()
LOOKAHEAD(path()) path() | identification_variable() | groupby_extension()
}
void groupby_extension() #GROUPBYEXTENSION(extensionsEnabled) : { }
{
scalar_function()
}
@ -841,6 +855,12 @@ void datetime_comp() : { }
)
}
void scalar_function() : { }
{
functions_returning_numerics()
| functions_returning_datetime()
| functions_returning_strings()
}
void arithmetic_value() : { }
{
@ -1073,7 +1093,14 @@ void orderby_clause() #ORDERBY : { }
void orderby_item() #ORDERBYITEM : { }
{
path() [ <ASC> #ASCENDING | <DESC> #DESCENDING ]
(LOOKAHEAD(path()) path() | orderby_extension())
[ <ASC> #ASCENDING | <DESC> #DESCENDING ]
}
void orderby_extension() #ORDERBYEXTENSION(extensionsEnabled) : { }
{
aggregate_select_expression()
}

View File

@ -0,0 +1,30 @@
/*
* 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.jdbc.query;
import javax.persistence.Query;
import org.apache.openjpa.persistence.query.GroupingTestCase;
public class TestJDBCGrouping extends GroupingTestCase {
protected void prepareQuery(Query q) {
// nothing to do for JDBC case
}
}

View File

@ -0,0 +1,277 @@
package org.apache.openjpa.persistence.query;
import java.util.*;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.apache.openjpa.persistence.test.SingleEMTestCase;
import org.apache.openjpa.persistence.simple.AllFieldTypes;
import org.apache.openjpa.persistence.ArgumentException;
/**
* <p>Tests grouping and having capabilities.</p>
*
* @author Abe White
*/
public abstract class GroupingTestCase
extends SingleEMTestCase {
protected abstract void prepareQuery(Query q);
public void setUp() {
super.setUp(AllFieldTypes.class, CLEAR_TABLES, "openjpa.Log", "SQL=TRACE");
AllFieldTypes pc1 = new AllFieldTypes();
AllFieldTypes pc2 = new AllFieldTypes();
AllFieldTypes pc3 = new AllFieldTypes();
AllFieldTypes pc4 = new AllFieldTypes();
// pc1 and pc2, pc3 and pc4 grouped on intField, shortField
pc1.setIntField(1);
pc1.setShortField((short) -1);
pc2.setIntField(1);
pc2.setShortField((short) -1);
pc3.setIntField(2);
pc3.setShortField((short) -2);
pc4.setIntField(2);
pc4.setShortField((short) -2);
// pc1 and pc2 grouped on stringField
pc1.setStringField("abc");
pc2.setStringField("acd");
pc3.setStringField("def");
pc4.setStringField("efg");
// pc2 and pc3 grouped on byteField
pc2.setByteField((byte) 1);
pc3.setByteField((byte) 1);
pc1.setByteField((byte) 0);
pc4.setByteField((byte) 2);
// longField is unique id
pc1.setLongField(1L);
pc2.setLongField(2L);
pc3.setLongField(3L);
pc4.setLongField(4L);
// set up some relations
pc1.setSelfOneOne(pc4);
pc2.setSelfOneOne(pc3);
pc3.setSelfOneOne(pc2);
pc4.setSelfOneOne(pc1);
// if variable testing, set up some 1-Ms instead of the 1-1s above
if (getName().startsWith("testVariable")) {
pc1.setSelfOneOne(pc1);
pc2.setSelfOneOne(pc1);
pc1.getSelfOneMany().add(pc1);
pc1.getSelfOneMany().add(pc2);
pc3.setSelfOneOne(pc3);
pc4.setSelfOneOne(pc3);
pc3.getSelfOneMany().add(pc3);
pc3.getSelfOneMany().add(pc4);
}
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(pc1);
em.persist(pc2);
em.persist(pc3);
em.persist(pc4);
em.getTransaction().commit();
em.close();
}
public void testSimpleGroup() {
Query q = em.createQuery("select o.intField from AllFieldTypes o " +
"group by o.intField order by o.intField asc");
prepareQuery(q);
List res = q.getResultList();
assertEquals(2, res.size());
Iterator itr = res.iterator();
assertEquals(new Integer(1), itr.next());
assertEquals(new Integer(2), itr.next());
assertTrue(!itr.hasNext());
}
public void testOrderByAggregate() {
// this is an extension of JPQL
Query q = em.createQuery("select sum(o.shortField) " +
"from AllFieldTypes o"
+ " group by o.intField order by sum(o.shortField) asc");
prepareQuery(q);
// this might fail in MySQL
List res = q.getResultList();
assertEquals(2, res.size());
Iterator itr = res.iterator();
assertEquals(new Long(-4), itr.next());
assertEquals(new Long(-2), itr.next());
assertTrue(!itr.hasNext());
}
public void testCompoundGroupSame() {
Query q = em.createQuery("select o.intField from AllFieldTypes o " +
"group by o.intField, o.shortField order by o.shortField asc");
prepareQuery(q);
List res = q.getResultList();
assertEquals(2, res.size());
Iterator itr = res.iterator();
assertEquals(new Integer(2), itr.next());
assertEquals(new Integer(1), itr.next());
assertTrue(!itr.hasNext());
}
public void testCompoundGroupDifferent() {
Query q = em.createQuery("select o.intField from AllFieldTypes o " +
"group by o.intField, o.byteField order by o.intField asc");
prepareQuery(q);
List res = q.getResultList();
assertEquals(4, res.size());
Iterator itr = res.iterator();
assertEquals(new Integer(1), itr.next());
assertEquals(new Integer(1), itr.next());
assertEquals(new Integer(2), itr.next());
assertEquals(new Integer(2), itr.next());
assertTrue(!itr.hasNext());
}
public void testDifferentGroupLengths() {
Query q = em.createQuery("select o.byteField from AllFieldTypes o"
+ " group by o.byteField order by o.byteField asc");
prepareQuery(q);
List res = q.getResultList();
assertEquals(3, res.size());
Iterator itr = res.iterator();
assertEquals((byte) 0, itr.next());
assertEquals((byte) 1, itr.next());
assertEquals((byte) 2, itr.next());
assertTrue(!itr.hasNext());
}
public void testGroupRelationField() {
Query q = em.createQuery("select o.selfOneOne.intField " +
"from AllFieldTypes o group by o.selfOneOne.intField " +
"order by o.selfOneOne.intField asc");
prepareQuery(q);
List res = q.getResultList();
assertEquals(2, res.size());
Iterator itr = res.iterator();
assertEquals(new Integer(1), itr.next());
assertEquals(new Integer(2), itr.next());
assertTrue(!itr.hasNext());
}
public void testSubstringInGroupBy() {
// this is an extension of JPQL
Query q = em.createQuery("select substring(o.stringField, 1, 1), " +
"count(o) from AllFieldTypes o " +
"group by substring(o.stringField, 1, 1)");
prepareQuery(q);
List res = q.getResultList();
assertEquals(3, res.size());
q = em.createQuery("select substring(o.stringField, 1, 2), count(o) " +
"from AllFieldTypes o group by substring(o.stringField, 1, 2)");
prepareQuery(q);
res = q.getResultList();
assertEquals(4, res.size());
}
public void testGroupedAggregate() {
Query q = em.createQuery("select count(o) from AllFieldTypes o " +
"group by o.byteField order by o.byteField asc");
prepareQuery(q);
List res = q.getResultList();
assertEquals(3, res.size());
Iterator itr = res.iterator();
assertEquals(new Long(1), itr.next());
assertEquals(new Long(2), itr.next());
assertEquals(new Long(1), itr.next());
assertTrue(!itr.hasNext());
}
public void testGroupedRelationAggregate() {
Query q = em.createQuery("select count(o), max(o.selfOneOne.longField)"
+ " from AllFieldTypes o group by o.intField"
+ " order by o.intField asc");
List res = q.getResultList();
assertEquals(2, res.size());
Iterator itr = res.iterator();
Object[] o = (Object[]) itr.next();
assertEquals(new Long(2), o[0]);
assertEquals(new Long(4), o[1]);
o = (Object[]) itr.next();
assertEquals(new Long(2), o[0]);
assertEquals(new Long(2), o[1]);
assertTrue(!itr.hasNext());
}
public void testGroupedMixedProjection() {
Query q = em.createQuery("select count(o), o.shortField " +
"from AllFieldTypes o group by o.intField, o.shortField " +
"order by o.intField asc");
prepareQuery(q);
List res = q.getResultList();
assertEquals(2, res.size());
Iterator itr = res.iterator();
Object[] o = (Object[]) itr.next();
assertEquals(new Long(2), o[0]);
assertEquals(new Short((short) -1), o[1]);
o = (Object[]) itr.next();
assertEquals(new Long(2), o[0]);
assertEquals(new Short((short) -2), o[1]);
assertTrue(!itr.hasNext());
}
public void testSimpleHaving() {
Query q = em.createQuery("select o.intField from AllFieldTypes o " +
"group by o.intField having o.intField < 2");
prepareQuery(q);
assertEquals(new Integer(1), q.getSingleResult());
}
public void testAggregateHaving() {
Query q = em.createQuery("select o.byteField from AllFieldTypes o " +
"group by o.byteField having count(o) > 1");
prepareQuery(q);
assertEquals(new Byte((byte) 1), q.getSingleResult());
}
public void testMixedHaving() {
Query q = em.createQuery("select o.byteField from AllFieldTypes o " +
"group by o.byteField having count(o) > 1 or o.byteField = 0 " +
"order by o.byteField asc");
prepareQuery(q);
List res = q.getResultList();
assertEquals(2, res.size());
Iterator itr = res.iterator();
assertEquals(new Byte((byte) 0), itr.next());
assertEquals(new Byte((byte) 1), itr.next());
assertTrue(!itr.hasNext());
}
public void testVariableGroup() {
Query q = em.createQuery("select max(other.longField) " +
"from AllFieldTypes o, AllFieldTypes other " +
"where other member of o.selfOneMany " +
"group by other.intField order by other.intField asc");
prepareQuery(q);
List res = q.getResultList();
assertEquals(2, res.size());
Iterator itr = res.iterator();
assertEquals(new Long(2), itr.next());
assertEquals(new Long(4), itr.next());
assertTrue(!itr.hasNext());
}
public void testVariableHaving() {
Query q = em.createQuery("select max(o.longField), other.byteField " +
"from AllFieldTypes o, AllFieldTypes other " +
"where other member of o.selfOneMany " +
"group by other.byteField having sum(other.intField) = 2");
prepareQuery(q);
assertEquals(new Long(3), ((Object[])q.getSingleResult())[0]);
}
}

View File

@ -34,7 +34,7 @@ public class TestQueryPagination
extends SQLListenerTestCase {
public void setUp() {
setUp(SimpleEntity.class, CLEAR_TABLES, "openjpa.Log", "SQL=TRACE");
setUp(SimpleEntity.class, CLEAR_TABLES);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

View File

@ -0,0 +1,61 @@
/*
* 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.query;
import javax.persistence.EntityManager;
import org.apache.openjpa.persistence.test.SingleEMTestCase;
public class TestSubstring extends SingleEMTestCase {
public void setUp() {
super.setUp(SimpleEntity.class, CLEAR_TABLES, "openjpa.Log", "SQL=TRACE");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(new SimpleEntity("foo", "bar"));
em.getTransaction().commit();
em.close();
}
public void testSingleCharacterSubstringInWhere() {
assertEquals((long) 1, em.createQuery("select count(o) from simple o " +
"where substring(o.value, 1, 1) = 'b'").getSingleResult());
assertEquals((long) 1, em.createQuery("select count(o) from simple o " +
"where substring(o.value, 2, 1) = 'a'").getSingleResult());
assertEquals((long) 1, em.createQuery("select count(o) from simple o " +
"where substring(o.value, 3, 1) = 'r'").getSingleResult());
}
public void testMultiCharacterSubstringInWhere() {
assertEquals((long) 1, em.createQuery("select count(o) from simple o " +
"where substring(o.value, 1, 2) = 'ba'").getSingleResult());
assertEquals((long) 1, em.createQuery("select count(o) from simple o " +
"where substring(o.value, 2, 2) = 'ar'").getSingleResult());
}
public void testSubstringInSelect() {
assertEquals("b", em.createQuery("select substring(o.value, 1, 1) " +
"from simple o").getSingleResult());
assertEquals("a", em.createQuery("select substring(o.value, 2, 1) " +
"from simple o").getSingleResult());
assertEquals("r", em.createQuery("select substring(o.value, 3, 1) " +
"from simple o").getSingleResult());
}
}

View File

@ -25,14 +25,18 @@ import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.List;
import java.util.ArrayList;
import javax.persistence.Entity;
import javax.persistence.Version;
import javax.persistence.OneToOne;
import javax.persistence.OneToMany;
import org.apache.openjpa.persistence.PersistentCollection;
@Entity
public class AllFieldTypes {
public static enum EnumType {Value1, Value2};
// @Basic types
@ -74,6 +78,12 @@ public class AllFieldTypes {
@PersistentCollection
private int[] arrayOfInts;
// one-to-one and one-to-many relations to self
@OneToOne
private AllFieldTypes selfOneOne;
@OneToMany
private List<AllFieldTypes> selfOneMany = new ArrayList<AllFieldTypes>();
public void setShortField(short shortField) {
this.shortField = shortField;
}
@ -338,5 +348,20 @@ public class AllFieldTypes {
wShortField = shortField;
}
public AllFieldTypes getSelfOneOne() {
return selfOneOne;
}
public void setSelfOneOne(AllFieldTypes selfOneOne) {
this.selfOneOne = selfOneOne;
}
public List<AllFieldTypes> getSelfOneMany() {
return selfOneMany;
}
public void setSelfOneMany(List<AllFieldTypes> selfOneMany) {
this.selfOneMany = selfOneMany;
}
}