mirror of https://github.com/apache/openjpa.git
OPENJPA-1266: JDBC escape syntax for date, time, timestamp
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@807851 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f61ff60842
commit
e19c75a9c3
|
@ -44,6 +44,9 @@ public class Lit
|
|||
public Lit(Object val, int ptype) {
|
||||
_val = val;
|
||||
_ptype = ptype;
|
||||
if (_ptype == Literal.TYPE_DATE || _ptype == Literal.TYPE_TIME ||
|
||||
_ptype == Literal.TYPE_TIMESTAMP)
|
||||
_isRaw = true;
|
||||
}
|
||||
|
||||
public Class getType() {
|
||||
|
@ -116,7 +119,8 @@ public class Lit
|
|||
sql.appendValue(((Object[]) lstate.sqlValue)[index],
|
||||
lstate.getColumn(index));
|
||||
else if (_isRaw) {
|
||||
if (getParseType() == Literal.TYPE_ENUM) {
|
||||
int parseType = getParseType();
|
||||
if (parseType == Literal.TYPE_ENUM) {
|
||||
StringBuilder value = new StringBuilder();
|
||||
boolean isOrdinal = false;
|
||||
if (lstate.sqlValue instanceof Integer)
|
||||
|
@ -128,6 +132,10 @@ public class Lit
|
|||
value.append("'");
|
||||
lstate.sqlValue = new Raw(value.toString());
|
||||
_rawVal = lstate.sqlValue;
|
||||
} else if (parseType == Literal.TYPE_DATE || parseType == Literal.TYPE_TIME ||
|
||||
parseType == Literal.TYPE_TIMESTAMP) {
|
||||
lstate.sqlValue = new Raw(_val.toString());
|
||||
_rawVal = lstate.sqlValue;
|
||||
} else {
|
||||
lstate.sqlValue = new Raw(_val instanceof String ? "'"+_val+"'" : _val.toString());
|
||||
_rawVal = lstate.sqlValue;
|
||||
|
|
|
@ -35,6 +35,9 @@ public interface Literal
|
|||
public static final int TYPE_CLASS = 5;
|
||||
public static final int TYPE_ENUM = 6;
|
||||
public static final int TYPE_COLLECTION = 7;
|
||||
public static final int TYPE_DATE = 8;
|
||||
public static final int TYPE_TIME = 9;
|
||||
public static final int TYPE_TIMESTAMP = 10;
|
||||
|
||||
/**
|
||||
* The value of this literal.
|
||||
|
|
|
@ -1375,6 +1375,15 @@ public class JPQLExpressionBuilder
|
|||
assertQueryExtensions("ORDER BY");
|
||||
return eval(onlyChild(node));
|
||||
|
||||
case JJTDATELITERAL:
|
||||
return factory.newLiteral(node.text, Literal.TYPE_DATE);
|
||||
|
||||
case JJTTIMELITERAL:
|
||||
return factory.newLiteral(node.text, Literal.TYPE_TIME);
|
||||
|
||||
case JJTTIMESTAMPLITERAL:
|
||||
return factory.newLiteral(node.text, Literal.TYPE_TIMESTAMP);
|
||||
|
||||
default:
|
||||
throw parseException(EX_FATAL, "bad-tree",
|
||||
new Object[]{ node }, null);
|
||||
|
|
|
@ -293,6 +293,24 @@ TOKEN : /* literals */
|
|||
)
|
||||
"'"
|
||||
>
|
||||
| < DATE_LITERAL: "{d '" (["0"-"9"])(["0"-"9"])(["0"-"9"])(["0"-"9"]) ("-")
|
||||
(["0"-"1"])(["0"-"9"]) ("-")
|
||||
(["0"-"3"])(["0"-"9"]) "'}"
|
||||
>
|
||||
| < TIME_LITERAL: "{t '" (["0"-"2"])(["0"-"9"]) (":")
|
||||
(["0"-"6"])(["0"-"9"]) (":")
|
||||
(["0"-"6"])(["0"-"9"]) "'}"
|
||||
>
|
||||
| < TIMESTAMP_LITERAL: "{ts '" (["0"-"9"])(["0"-"9"])(["0"-"9"])(["0"-"9"]) ("-")
|
||||
(["0"-"1"])(["0"-"9"]) ("-")
|
||||
(["0"-"3"])(["0"-"9"]) (" ")
|
||||
(["0"-"2"])(["0"-"9"]) (":")
|
||||
(["0"-"6"])(["0"-"9"]) (":")
|
||||
(["0"-"6"])(["0"-"9"])
|
||||
((".") (["0"-"9"]) (["0"-"9"])? (["0"-"9"])? (["0"-"9"])?
|
||||
(["0"-"9"])? (["0"-"9"])? )?
|
||||
"'}"
|
||||
>
|
||||
}
|
||||
|
||||
TOKEN [ IGNORE_CASE ]: /* boolean literals can be case-insensitive */
|
||||
|
@ -1105,6 +1123,7 @@ void datetime_expression() : { }
|
|||
|
||||
void datetime_primary() : { }
|
||||
{
|
||||
date_literal() | time_literal() | timestamp_literal() |
|
||||
LOOKAHEAD(path()) path() | functions_returning_datetime() | input_parameter() | aggregate_select_expression()
|
||||
| LOOKAHEAD(qualified_path()) qualified_path()
|
||||
| LOOKAHEAD(general_identification_variable()) general_identification_variable()
|
||||
|
@ -1408,7 +1427,8 @@ void path_component() #IDENTIFICATIONVARIABLE :
|
|||
|
||||
void literal() : { }
|
||||
{
|
||||
numeric_literal() | boolean_literal() | string_literal() | enum_literal()
|
||||
numeric_literal() | boolean_literal() | string_literal() | enum_literal() | date_literal() |
|
||||
time_literal() | timestamp_literal()
|
||||
}
|
||||
|
||||
|
||||
|
@ -1446,6 +1466,27 @@ void string_literal() #STRINGLITERAL :
|
|||
}
|
||||
|
||||
|
||||
void date_literal() #DATELITERAL :
|
||||
{ Token t; }
|
||||
{
|
||||
t = <DATE_LITERAL> { jjtThis.setToken (t); }
|
||||
}
|
||||
|
||||
|
||||
void time_literal() #TIMELITERAL :
|
||||
{ Token t; }
|
||||
{
|
||||
t = <TIME_LITERAL> { jjtThis.setToken (t); }
|
||||
}
|
||||
|
||||
|
||||
void timestamp_literal() #TIMESTAMPLITERAL :
|
||||
{ Token t; }
|
||||
{
|
||||
t = <TIMESTAMP_LITERAL> { jjtThis.setToken (t); }
|
||||
}
|
||||
|
||||
|
||||
void input_parameter() : { }
|
||||
{
|
||||
named_input_parameter() | positional_input_parameter()
|
||||
|
|
|
@ -18,11 +18,15 @@
|
|||
*/
|
||||
package org.apache.openjpa.persistence.query;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
@NamedQueries( {
|
||||
@NamedQuery(name = "Employee.findByName",
|
||||
|
@ -42,6 +46,15 @@ public class Employee {
|
|||
|
||||
private int statusId;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date hireDate;
|
||||
|
||||
@Temporal(TemporalType.TIME)
|
||||
private Date hireTime;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date hireTimestamp;
|
||||
|
||||
public int getStatusId() {
|
||||
return statusId;
|
||||
}
|
||||
|
@ -74,5 +87,28 @@ public class Employee {
|
|||
this.someLong = someLong;
|
||||
}
|
||||
|
||||
public Date getHireDate() {
|
||||
return hireDate;
|
||||
}
|
||||
|
||||
public void setHireDate(Date hireDate) {
|
||||
this.hireDate = hireDate;
|
||||
}
|
||||
|
||||
public Date getHireTime() {
|
||||
return hireTime;
|
||||
}
|
||||
|
||||
public void setHireTime(Date hireTime) {
|
||||
this.hireTime = hireTime;
|
||||
}
|
||||
|
||||
public Date getHireTimestamp() {
|
||||
return hireTimestamp;
|
||||
}
|
||||
|
||||
public void setHireTimestamp(Date hireTimestamp) {
|
||||
this.hireTimestamp = hireTimestamp;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityTransaction;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
|
||||
/**
|
||||
* Test JDBC escape syntax for date, time, and timestamp literals
|
||||
*/
|
||||
public class TestJDBCEscapeDate extends SingleEMFTestCase {
|
||||
|
||||
public void setUp() {
|
||||
setUp(Employee.class, DROP_TABLES);
|
||||
}
|
||||
|
||||
public void testJDBCEscape() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
EntityTransaction tran = em.getTransaction();
|
||||
Employee e = new Employee();
|
||||
e.setEmpId(1);
|
||||
e.setName("name1");
|
||||
e.setHireDate(new Date());
|
||||
e.setHireTime(new Date());
|
||||
e.setHireTimestamp(new Date());
|
||||
em.persist(e);
|
||||
tran.begin();
|
||||
em.flush();
|
||||
tran.commit();
|
||||
em.clear();
|
||||
|
||||
String[] jpql = {
|
||||
"select a from Employee a where a.hireDate >= {d '2009-08-25'}",
|
||||
"select a from Employee a where a.hireTime >= {t '00:00:00'}",
|
||||
"select a from Employee a where a.hireTimestamp >= {ts '2009-08-25 00:00:00'}",
|
||||
"select a from Employee a where a.hireTimestamp >= {ts '2009-08-25 00:00:00.1'}",
|
||||
"select a from Employee a where a.hireTimestamp >= {ts '2009-08-25 00:00:00.11'}",
|
||||
"select a from Employee a where a.hireTimestamp >= {ts '2009-08-25 00:00:00.111'}",
|
||||
"select a from Employee a where a.hireTimestamp >= {ts '2009-08-25 00:00:00.1111'}",
|
||||
"select a from Employee a where a.hireTimestamp >= {ts '2009-08-25 00:00:00.11111'}",
|
||||
"select a from Employee a where a.hireTimestamp >= {ts '2009-08-25 00:00:00.111111'}",
|
||||
"select {t '00:00:00'}, a.empId from Employee a",
|
||||
};
|
||||
|
||||
for (int i = 0; i < jpql.length; i++) {
|
||||
Query q = em.createQuery(jpql[i]);
|
||||
List results = q.getResultList();
|
||||
Assert.assertEquals(1, results.size());
|
||||
}
|
||||
|
||||
String wrongTs = "select a from Employee a where a.hireTimestamp > {ts '2009-08-25 00:00:00.1111111'}";
|
||||
try {
|
||||
Query q = em.createQuery(wrongTs);
|
||||
List results = q.getResultList();
|
||||
Assert.fail();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
|
||||
em.getTransaction().begin();
|
||||
String update = "update Employee a set a.hireTimestamp = {ts '2009-08-25 00:00:00.111111'} where a.empId = 1";
|
||||
Query q = em.createQuery(update);
|
||||
int updateCnt = q.executeUpdate();
|
||||
em.getTransaction().commit();
|
||||
Assert.assertEquals(1, updateCnt);
|
||||
em.close();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue