mirror of https://github.com/apache/openjpa.git
OPENJPA-2557: FinderCache contains incorrectly cached query with a NULL for a Primary Key.
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1662615 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
8129fe685b
commit
6591d4d464
|
@ -72,7 +72,17 @@ public class FinderQueryImpl
|
||||||
return null;
|
return null;
|
||||||
SQLBuffer buffer = impl.getSQL();
|
SQLBuffer buffer = impl.getSQL();
|
||||||
Column[] pkCols = mapping.getPrimaryKeyColumns();
|
Column[] pkCols = mapping.getPrimaryKeyColumns();
|
||||||
boolean canCache = pkCols.length == buffer.getParameters().size();
|
|
||||||
|
//OPENJPA-2557: Typically the number of pkCols (length) should match the number (size) of
|
||||||
|
//parameters. However, there are a few cases (e.g. when extra parameters are needed for
|
||||||
|
//discriminator data) where the pkCols length may be different than the parameters.
|
||||||
|
//If we find the number of pkCols is equal to the number of parameters, we need to do
|
||||||
|
//one last check to verify that the buffers columns match the pkCols exactly.
|
||||||
|
boolean canCache = (pkCols.length == buffer.getParameters().size());
|
||||||
|
for(int i=0; i < pkCols.length && canCache; i++){
|
||||||
|
canCache = canCache && buffer.getColumns().contains(pkCols[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return (canCache)
|
return (canCache)
|
||||||
? new FinderQueryImpl(mapping, impl, buffer) : null;
|
? new FinderQueryImpl(mapping, impl, buffer) : null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* 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.sqlcache.discrim;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import javax.persistence.DiscriminatorColumn;
|
||||||
|
import javax.persistence.DiscriminatorType;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@DiscriminatorColumn(discriminatorType = DiscriminatorType.INTEGER, name = "EXTDISCR")
|
||||||
|
public class AbstractExtValue implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 7753311252101420833L;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return this.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((code == null) ? 0 : code.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
AbstractExtValue other = (AbstractExtValue) obj;
|
||||||
|
if (code == null) {
|
||||||
|
if (other.code != null)
|
||||||
|
return false;
|
||||||
|
} else if (!code.equals(other.code))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* 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.sqlcache.discrim;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public class ComposedPK implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -7415701271873221026L;
|
||||||
|
|
||||||
|
private Short field1;
|
||||||
|
|
||||||
|
private Integer field2;
|
||||||
|
|
||||||
|
public ComposedPK(){}
|
||||||
|
|
||||||
|
public Short getField1() {
|
||||||
|
return field1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setField1(Short field1) {
|
||||||
|
this.field1 = field1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getField2() {
|
||||||
|
return field2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setField2(Integer field2) {
|
||||||
|
this.field2 = field2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComposedPK(Short field1, Integer field2) {
|
||||||
|
this.field1 = field1;
|
||||||
|
this.field2 = field2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((field1 == null) ? 0 : field1.hashCode());
|
||||||
|
result = prime * result + ((field2 == null) ? 0 : field2.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
ComposedPK other = (ComposedPK) obj;
|
||||||
|
if (field1 == null) {
|
||||||
|
if (other.field1 != null)
|
||||||
|
return false;
|
||||||
|
} else if (!field1.equals(other.field1))
|
||||||
|
return false;
|
||||||
|
if (field2 == null) {
|
||||||
|
if (other.field2 != null)
|
||||||
|
return false;
|
||||||
|
} else if (!field2.equals(other.field2))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* 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.sqlcache.discrim;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import javax.persistence.DiscriminatorValue;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@DiscriminatorValue("9")
|
||||||
|
public class ExtValue1 extends AbstractExtValue implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -6800461627353149172L;
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* 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.sqlcache.discrim;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
|
||||||
|
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
||||||
|
import org.apache.openjpa.kernel.FetchConfiguration;
|
||||||
|
import org.apache.openjpa.kernel.FinderCache;
|
||||||
|
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||||
|
|
||||||
|
|
||||||
|
public class TestFinderCacheWithNulls extends SingleEMFTestCase {
|
||||||
|
private FetchConfiguration fetchCfg;
|
||||||
|
private FinderCache fndrCache;
|
||||||
|
private ClassMapping clsMapping_UserData;
|
||||||
|
private ClassMapping clsMapping_AbstractExtValue;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp(AbstractExtValue.class, ComposedPK.class, ExtValue1.class, UserData.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test() {
|
||||||
|
|
||||||
|
init();
|
||||||
|
initData();
|
||||||
|
|
||||||
|
EntityManager em = this.emf.createEntityManager();
|
||||||
|
|
||||||
|
assertNull(fndrCache.get(clsMapping_UserData, fetchCfg));
|
||||||
|
|
||||||
|
UserData usrData=em.find(UserData.class, new ComposedPK(Short.valueOf("2"), null));
|
||||||
|
assertNull(usrData);
|
||||||
|
//FinderCache should be empty. That is, since the previous find contained a NULL,
|
||||||
|
//the cache shouldn't not contain the finder SQL. However, prior to OPENJPA-2557,
|
||||||
|
//the finder cache contain the finder SQL with the NULL value. With this
|
||||||
|
//JIRA, the cache should not contain the finder.
|
||||||
|
assertNull(fndrCache.get(clsMapping_UserData, fetchCfg));
|
||||||
|
em.clear();
|
||||||
|
|
||||||
|
usrData=em.find(UserData.class, new ComposedPK(Short.valueOf("2"), 3));
|
||||||
|
//Prior to OPENJPA-2557, the UserData would not have been found because the previous
|
||||||
|
//find with a NULL would have been cached.
|
||||||
|
assertNotNull(usrData);
|
||||||
|
assertNull(fndrCache.get(clsMapping_UserData, fetchCfg));
|
||||||
|
em.clear();
|
||||||
|
|
||||||
|
ExtValue1 ev1 = em.find(ExtValue1.class, "A");
|
||||||
|
assertNotNull(ev1);
|
||||||
|
assertNotNull(fndrCache.get(clsMapping_AbstractExtValue, fetchCfg));
|
||||||
|
em.clear();
|
||||||
|
|
||||||
|
fndrCache.invalidate(clsMapping_AbstractExtValue);
|
||||||
|
assertNull(fndrCache.get(clsMapping_AbstractExtValue, fetchCfg));
|
||||||
|
|
||||||
|
AbstractExtValue aev = em.find(AbstractExtValue.class, "A");
|
||||||
|
assertNotNull(aev);
|
||||||
|
assertNotNull(fndrCache.get(clsMapping_AbstractExtValue, fetchCfg));
|
||||||
|
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(){
|
||||||
|
EntityManager em = emf.createEntityManager();
|
||||||
|
|
||||||
|
JDBCConfiguration conf = (JDBCConfiguration) emf.getConfiguration();
|
||||||
|
clsMapping_UserData = conf.getMappingRepositoryInstance().getMapping(UserData.class, null, true);
|
||||||
|
clsMapping_AbstractExtValue = conf.getMappingRepositoryInstance().
|
||||||
|
getMapping(AbstractExtValue.class, null, true);
|
||||||
|
|
||||||
|
fetchCfg = ((org.apache.openjpa.persistence.EntityManagerImpl) em).getBroker().getFetchConfiguration();
|
||||||
|
|
||||||
|
fndrCache = ((JDBCConfiguration) emf.getConfiguration()).getFinderCacheInstance();
|
||||||
|
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initData() {
|
||||||
|
EntityManager em = emf.createEntityManager();
|
||||||
|
|
||||||
|
ExtValue1 extValue1 = new ExtValue1();
|
||||||
|
extValue1.setCode("A");
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist(extValue1);
|
||||||
|
em.flush();
|
||||||
|
|
||||||
|
ComposedPK pK = new ComposedPK((short) 2, 3);
|
||||||
|
UserData userData = new UserData();
|
||||||
|
userData.setPk(pK);
|
||||||
|
userData.setExtValue(extValue1);
|
||||||
|
em.persist(userData);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* 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.sqlcache.discrim;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import javax.persistence.EmbeddedId;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "TB1")
|
||||||
|
public class UserData implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 158985341763605994L;
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private ComposedPK pk;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "EXT_USR", insertable = false, updatable = false)
|
||||||
|
private ExtValue1 extValue;
|
||||||
|
|
||||||
|
public ExtValue1 getExtValue() {
|
||||||
|
return extValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtValue(ExtValue1 val) {
|
||||||
|
this.extValue = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComposedPK getPk() {
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPk(ComposedPK pk) {
|
||||||
|
this.pk = pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((extValue == null) ? 0 : extValue.hashCode());
|
||||||
|
result = prime * result + ((pk == null) ? 0 : pk.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
UserData other = (UserData) obj;
|
||||||
|
if (extValue == null) {
|
||||||
|
if (other.extValue != null)
|
||||||
|
return false;
|
||||||
|
} else if (!extValue.equals(other.extValue))
|
||||||
|
return false;
|
||||||
|
if (pk == null) {
|
||||||
|
if (other.pk != null)
|
||||||
|
return false;
|
||||||
|
} else if (!pk.equals(other.pk))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue