OPENJPA-2849 proper handling of different Date types

This commit is contained in:
Mark Struberg 2021-05-07 23:07:41 +02:00
parent 477d73a996
commit 25af7c35ee
3 changed files with 211 additions and 160 deletions

View File

@ -132,6 +132,11 @@ abstract class UnaryOp
throws SQLException { throws SQLException {
Class<?> type = getType(); Class<?> type = getType();
int typeCode = type != null ? JavaTypes.getTypeCode(type) : JavaSQLTypes.JDBC_DEFAULT; int typeCode = type != null ? JavaTypes.getTypeCode(type) : JavaSQLTypes.JDBC_DEFAULT;
if (typeCode == JavaTypes.DATE) {
// further clarify which date exactly
typeCode = JavaSQLTypes.getDateTypeCode(type);
}
Object value = res.getObject(this, typeCode, null); Object value = res.getObject(this, typeCode, null);
if (value == null) { if (value == null) {
if (nullableValue(ctx, state)) { // OPENJPA-1794 if (nullableValue(ctx, state)) { // OPENJPA-1794

View File

@ -1,160 +1,184 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one * Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file * or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information * distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file * regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the * to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance * "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at * with the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, * Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an * software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the * KIND, either express or implied. See the License for the
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.apache.openjpa.jira1794; package org.apache.openjpa.jira1794;
import javax.persistence.Entity; import java.util.Date;
import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity import javax.persistence.Table;
@Table(name = "j1794_ae")
public class AggEntity { @Entity
@Table(name = "j1794_ae")
@Id public class AggEntity {
@GeneratedValue
private int id; @Id
@GeneratedValue
private short pshortVal; private int id;
private Short shortVal;
private short pshortVal;
private int pintVal; private Short shortVal;
private Integer intVal;
private int pintVal;
private long plongVal; private Integer intVal;
private Long longVal;
private long plongVal;
private float pfloatVal; private Long longVal;
private Float floatVal;
private float pfloatVal;
private double pdblVal; private Float floatVal;
private Double dblVal;
private double pdblVal;
private String stringVal; private Double dblVal;
public void setId(int id) { private String stringVal;
this.id = id;
} private java.util.Date utilDate;
public int getId() { private java.sql.Date sqlDate;
return id;
} public void setId(int id) {
this.id = id;
public void setPshortVal(short pshortVal) { }
this.pshortVal = pshortVal;
} public int getId() {
return id;
public short getPshortVal() { }
return pshortVal;
} public void setPshortVal(short pshortVal) {
this.pshortVal = pshortVal;
public void setShortVal(Short pShortVal) { }
this.shortVal = pShortVal;
} public short getPshortVal() {
return pshortVal;
public Short getShortVal() { }
return shortVal;
} public void setShortVal(Short pShortVal) {
this.shortVal = pShortVal;
public void setPintVal(int pintVal) { }
this.pintVal = pintVal;
} public Short getShortVal() {
return shortVal;
public int getPintVal() { }
return pintVal;
} public void setPintVal(int pintVal) {
this.pintVal = pintVal;
public void setIntVal(Integer intVal) { }
this.intVal = intVal;
} public int getPintVal() {
return pintVal;
public Integer getIntVal() { }
return intVal;
} public void setIntVal(Integer intVal) {
this.intVal = intVal;
public void setPlongVal(long plongVal) { }
this.plongVal = plongVal;
} public Integer getIntVal() {
return intVal;
public long getPlongVal() { }
return plongVal;
} public void setPlongVal(long plongVal) {
this.plongVal = plongVal;
public void setLongVal(Long longVal) { }
this.longVal = longVal;
} public long getPlongVal() {
return plongVal;
public Long getLongVal() { }
return longVal;
} public void setLongVal(Long longVal) {
this.longVal = longVal;
public void setPfloatVal(float pfloatVal) { }
this.pfloatVal = pfloatVal;
} public Long getLongVal() {
return longVal;
public float getPfloatVal() { }
return pfloatVal;
} public void setPfloatVal(float pfloatVal) {
this.pfloatVal = pfloatVal;
public void setFloatVal(Float floatVal) { }
this.floatVal = floatVal;
} public float getPfloatVal() {
return pfloatVal;
public Float getFloatVal() { }
return floatVal;
} public void setFloatVal(Float floatVal) {
this.floatVal = floatVal;
public void setPdblVal(double pdblVal) { }
this.pdblVal = pdblVal;
} public Float getFloatVal() {
return floatVal;
public double getPdblVal() { }
return pdblVal;
} public void setPdblVal(double pdblVal) {
this.pdblVal = pdblVal;
public void setDblVal(Double dblVal) { }
this.dblVal = dblVal;
} public double getPdblVal() {
return pdblVal;
public Double getDblVal() { }
return dblVal;
} public void setDblVal(Double dblVal) {
this.dblVal = dblVal;
public void setStringVal(String stringVal) { }
this.stringVal = stringVal;
} public Double getDblVal() {
return dblVal;
public String getStringVal() { }
return stringVal;
} public void setStringVal(String stringVal) {
this.stringVal = stringVal;
public void init() { }
setPshortVal((short) 1);
setShortVal((short) 1); public String getStringVal() {
setIntVal(1); return stringVal;
setPintVal(1); }
setLongVal(1L);
setPlongVal(1L); public Date getUtilDate() {
setDblVal(1d); return utilDate;
setPdblVal(1d); }
setFloatVal(1f);
setPfloatVal(1f); public void setUtilDate(Date utilDate) {
setStringVal("1"); this.utilDate = utilDate;
} }
}
public java.sql.Date getSqlDate() {
return sqlDate;
}
public void setSqlDate(java.sql.Date sqlDate) {
this.sqlDate = sqlDate;
}
public void init() {
setPshortVal((short) 1);
setShortVal((short) 1);
setIntVal(1);
setPintVal(1);
setLongVal(1L);
setPlongVal(1L);
setDblVal(1d);
setPdblVal(1d);
setFloatVal(1f);
setPfloatVal(1f);
setStringVal("1");
setUtilDate(new java.util.Date());
setSqlDate(new java.sql.Date(getUtilDate().getTime()));
}
}

View File

@ -75,6 +75,9 @@ public class TestAggregateFunctions extends SingleEMFTestCase {
verifyResult(em, stringAggregateFunctions, verifyResult(em, stringAggregateFunctions,
new String[] { "ae.stringVal" }, true, true); new String[] { "ae.stringVal" }, true, true);
verifyResult(em, stringAggregateFunctions,
new String[]{"ae.utilDate", "ae.sqlDate"}, true, true);
// Add a row to the table and re-test // Add a row to the table and re-test
AggEntity ae = new AggEntity(); AggEntity ae = new AggEntity();
ae.init(); ae.init();
@ -82,6 +85,8 @@ public class TestAggregateFunctions extends SingleEMFTestCase {
em.persist(ae); em.persist(ae);
em.getTransaction().commit(); em.getTransaction().commit();
verifyResult(em, stringAggregateFunctions, "ae.sqlDate", java.sql.Date.class);
// Verify all numeric types for all aggregate functions return a // Verify all numeric types for all aggregate functions return a
// non-null value when there is a query result // non-null value when there is a query result
verifyResult(em, numericAggregateFunctions, numericAttributes, false); verifyResult(em, numericAggregateFunctions, numericAttributes, false);
@ -90,6 +95,8 @@ public class TestAggregateFunctions extends SingleEMFTestCase {
verifyResult(em, stringAggregateFunctions, verifyResult(em, stringAggregateFunctions,
new String[] { "ae.stringVal" }, false); new String[] { "ae.stringVal" }, false);
verifyResult(em, stringAggregateFunctions, "ae.utilDate", java.util.Date.class);
em.close(); em.close();
} }
@ -241,6 +248,21 @@ public class TestAggregateFunctions extends SingleEMFTestCase {
} }
} }
private <T> void verifyResult(EntityManager em, String[] aggregates,
String attr, Class<T> expectedType) {
for (String func : aggregates) {
// JPQL with aggregate and aggregate in subselect
String sql = "SELECT " + func + "(" + attr + ")"
+ " FROM AggEntity ae WHERE " + attr + " <= "
+ "(SELECT " + func + "("
+ attr.replaceFirst("^ae.", "ae2.")
+ ") FROM AggEntity ae2)";
TypedQuery<T> q = em.createQuery(sql, expectedType);
T intance = q.getSingleResult();
assertEquals(intance.getClass(), expectedType);
}
}
private void verifyQueryResult(Query q, boolean emptyRs) { private void verifyQueryResult(Query q, boolean emptyRs) {
verifyQueryResult(q, emptyRs, false); verifyQueryResult(q, emptyRs, false);
} }