mirror of https://github.com/apache/openjpa.git
OPENJPA-975. Based on patch from B.J. Reed and Jody Grassel
git-svn-id: https://svn.apache.org/repos/asf/openjpa/branches/1.0.x@760911 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f47b3e3c1c
commit
716cf61d4e
|
@ -215,9 +215,12 @@ public class JDBCExpressionFactory
|
|||
String single, String multi, String esc) {
|
||||
if (!(v2 instanceof Const))
|
||||
throw new UserException(_loc.get("const-only", "matches"));
|
||||
return new MatchesExpression((Val) v1, (Const) v2, single, multi,
|
||||
esc != null ? esc : _type.getMappingRepository().
|
||||
getDBDictionary().searchStringEscape);
|
||||
if (esc == null && _type.getMappingRepository().
|
||||
getDBDictionary().requiresSearchStringEscapeForLike == true) {
|
||||
esc = _type.getMappingRepository().
|
||||
getDBDictionary().searchStringEscape;
|
||||
}
|
||||
return new MatchesExpression((Val) v1, (Const) v2, single, multi, esc);
|
||||
}
|
||||
|
||||
public Subquery newSubquery(ClassMetaData candidate, boolean subs,
|
||||
|
|
|
@ -208,6 +208,7 @@ public class DBDictionary
|
|||
public boolean requiresAliasForSubselect = false;
|
||||
public boolean allowsAliasInBulkClause = true;
|
||||
public boolean supportsMultipleNontransactionalResultSets = true;
|
||||
public boolean requiresSearchStringEscapeForLike = true;
|
||||
public String searchStringEscape = "\\";
|
||||
public boolean requiresCastForMathFunctions = false;
|
||||
public boolean requiresCastForComparisons = false;
|
||||
|
|
|
@ -20,8 +20,16 @@ package org.apache.openjpa.persistence.query;
|
|||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@NamedQueries( {
|
||||
@NamedQuery(name = "Employee.findByName",
|
||||
query = "Select e from Employee e where e.name LIKE :name") ,
|
||||
@NamedQuery(name = "Employee.findByNameEscaped",
|
||||
query = "Select e from Employee e where e.name LIKE :name ESCAPE '\\'")
|
||||
})
|
||||
@Entity
|
||||
@Table(name="SUBQ_EMPLOYEE")
|
||||
public class Employee {
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* 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 java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
|
||||
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
|
||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
|
||||
public class TestQueryEscapeCharacters
|
||||
extends SingleEMFTestCase {
|
||||
|
||||
public void setUp() {
|
||||
setUp(Employee.class, CLEAR_TABLES);
|
||||
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
Employee e = new Employee();
|
||||
e.setName("Mike Dick");
|
||||
e.setEmpId(1);
|
||||
em.persist(e);
|
||||
|
||||
e = new Employee();
|
||||
e.setName("Mike Jones");
|
||||
e.setEmpId(2);
|
||||
em.persist(e);
|
||||
|
||||
e = new Employee();
|
||||
e.setName("Mike Smith");
|
||||
e.setEmpId(3);
|
||||
em.persist(e);
|
||||
|
||||
e = new Employee();
|
||||
e.setName("M%ke Smith");
|
||||
e.setEmpId(4);
|
||||
em.persist(e);
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
em.createQuery("Delete from Employee").executeUpdate();
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testNormalQuery() {
|
||||
performFind ("Employee.findByName", "%Dick", 1);
|
||||
}
|
||||
|
||||
public void testMultiResultQuery() {
|
||||
performFind ("Employee.findByName", "Mike%", 3);
|
||||
}
|
||||
|
||||
public void testEscapedQuery() {
|
||||
performFind ("Employee.findByNameEscaped",
|
||||
"M\\%%", 1);
|
||||
}
|
||||
|
||||
public void testDoubleEscapedQuery() {
|
||||
performFind ("Employee.findByName", "\\\\", 0);
|
||||
}
|
||||
|
||||
public void testWrongEscape() {
|
||||
performFind ("Employee.findByName", "M|%%", 0);
|
||||
}
|
||||
|
||||
public void testDoubleSlashQuery() {
|
||||
// get the Dictionary and check the alwaysAddSearchString flag
|
||||
OpenJPAEntityManagerFactorySPI ojpaEmf =
|
||||
(OpenJPAEntityManagerFactorySPI) emf;
|
||||
JDBCConfiguration conf = (JDBCConfiguration)ojpaEmf.getConfiguration();
|
||||
|
||||
if (conf.getDBDictionaryInstance().
|
||||
requiresSearchStringEscapeForLike == true) {
|
||||
return;
|
||||
}
|
||||
|
||||
performFind ("Employee.findByName", "\\", 0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testDifferentEscapeCharacter () {
|
||||
OpenJPAEntityManagerFactorySPI ojpaEmf =
|
||||
(OpenJPAEntityManagerFactorySPI) emf;
|
||||
JDBCConfiguration conf = (JDBCConfiguration)ojpaEmf.getConfiguration();
|
||||
|
||||
// Would be nice to just pass a map to the createEntityManager, but
|
||||
// seems like it would be too much trouble to get the proper DB type
|
||||
// and then build the string for the map.
|
||||
conf.getDBDictionaryInstance().requiresSearchStringEscapeForLike = true;
|
||||
conf.getDBDictionaryInstance().searchStringEscape = "|";
|
||||
EntityManager em = emf.createEntityManager();
|
||||
|
||||
Query q = em.createNamedQuery("Employee.findByName");
|
||||
q.setParameter("name", "M|%%");
|
||||
List<Employee> emps = (List<Employee>) q.getResultList();
|
||||
assertEquals(1, emps.size());
|
||||
|
||||
String unnamedQuery =
|
||||
"Select e from Employee e where e.name LIKE :name";
|
||||
|
||||
q = em.createQuery(unnamedQuery);
|
||||
q.setParameter("name", "M|%%");
|
||||
emps = (List<Employee>) q.getResultList();
|
||||
assertEquals(1, emps.size());
|
||||
em.close();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void performFind (String namedQuery, String parameter,
|
||||
int expected) {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
|
||||
Query q = em.createNamedQuery(namedQuery);
|
||||
q.setParameter("name", parameter);
|
||||
List<Employee> emps = (List<Employee>) q.getResultList();
|
||||
assertEquals(expected, emps.size());
|
||||
|
||||
String unnamedQuery =
|
||||
"Select e from Employee e where e.name LIKE :name";
|
||||
if (namedQuery.equals("Employee.findByNameEscaped")) {
|
||||
unnamedQuery =
|
||||
"Select e from Employee e where e.name LIKE :name ESCAPE '\\'";
|
||||
}
|
||||
q = em.createQuery(unnamedQuery);
|
||||
q.setParameter("name", parameter);
|
||||
emps = (List<Employee>) q.getResultList();
|
||||
assertEquals(expected, emps.size());
|
||||
em.close();
|
||||
}
|
||||
}
|
|
@ -2400,6 +2400,44 @@ sequence value. May use a placeholder of <literal>{0}</literal> for the variable
|
|||
sequence name. Defaults to a database-appropriate value.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem id="DBDictionary.RequiresSearchStringEscapeForLike">
|
||||
<para>
|
||||
<indexterm>
|
||||
<primary>
|
||||
SQL
|
||||
</primary>
|
||||
<secondary>
|
||||
RequiresSearchStringEscapeForLike
|
||||
</secondary>
|
||||
</indexterm>
|
||||
<literal>RequiresSearchStringEscapeForLike</literal>:
|
||||
When true, the database requires an escape string for queries that use
|
||||
<literal>LIKE</literal>. The escape string can be specified using
|
||||
<literal>searchStringEscape</literal>. Defaults to <literal>true</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem id="DBDictionary.SearchStringEscape">
|
||||
<para>
|
||||
<indexterm>
|
||||
<primary>
|
||||
SQL
|
||||
</primary>
|
||||
<secondary>
|
||||
SearchStringEscape
|
||||
</secondary>
|
||||
</indexterm>
|
||||
<literal>SearchStringEscape</literal>:
|
||||
The default escape character used when generating SQL <literal>LIKE</literal>
|
||||
clauses. The escape character is used to escape the wildcard meaning of the
|
||||
<literal>_</literal> and <literal>%</literal> characters.
|
||||
Note: since JPQL provides the ability to define the escape character in
|
||||
the query, this setting is primarily used when translating other query
|
||||
languages, such as JDOQL. To not use any escape character, set the
|
||||
<literal>RequiresSearchStringEscapeForLike</literal> property to
|
||||
<literal>false</literal>. Defaults to <literal>"\\"</literal> (a single backslash
|
||||
in Java speak).
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section id="ref_guide_dbsetup_dbsupport_mysql">
|
||||
|
|
Loading…
Reference in New Issue