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:
Fay Wang 2009-08-25 23:22:59 +00:00
parent f61ff60842
commit e19c75a9c3
6 changed files with 190 additions and 2 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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()

View File

@ -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",
@ -41,7 +45,16 @@ public class Employee {
private long someLong;
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;
}
}

View File

@ -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();
}
}