Skip to content

Commit ea48bf2

Browse files
CAY-2911 Column Select Sometimes Null With Vertically Inherited Entity
1 parent 9782dad commit ea48bf2

22 files changed

Lines changed: 793 additions & 10 deletions

cayenne/src/main/java/org/apache/cayenne/access/jdbc/reader/EntityRowReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class EntityRowReader implements RowReader<DataRow> {
5454
this.entityName = classDescriptor.getEntity().getName();
5555
}
5656

57-
int segmentWidth = segmentMetadata.getFields().size();
57+
int segmentWidth = segmentMetadata.getColumnCount();
5858
this.startIndex = segmentMetadata.getColumnOffset();
5959
this.converters = new ExtendedType[segmentWidth];
6060
this.types = new int[segmentWidth];

cayenne/src/main/java/org/apache/cayenne/access/translator/select/DescriptorColumnExtractor.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,10 @@ public boolean visitToOne(ToOneProperty property) {
151151

152152
int count = result.getDbAttributes().size();
153153
for(int i=0; i<count; i++) {
154-
processTranslationResult(result, i);
155-
addEntityResultField(result.getDbAttributes().get(i));
154+
ResultNodeDescriptor resultNodeDescriptor = processTranslationResult(result, i);
155+
if(resultNodeDescriptor != null) {
156+
addEntityResultField(result.getDbAttributes().get(i));
157+
}
156158
}
157159

158160
return true;

cayenne/src/main/java/org/apache/cayenne/ejbql/parser/Compiler.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -291,9 +291,8 @@ public boolean visitToOne(ToOneProperty property) {
291291

292292
// append inheritance discriminator columns...
293293
for (ObjAttribute column : descriptor.getDiscriminatorColumns()) {
294-
295-
if (visited.add(column.getName())) {
296-
String dbAttributePath = column.getDbAttributePath().value();
294+
String dbAttributePath = column.getDbAttributePath().value();
295+
if (visited.add(dbAttributePath)) {
297296
compiledResult.addDbField(
298297
"fetch." + prefix + "." + dbAttributePath,
299298
prefix + "." + dbAttributePath);
@@ -363,8 +362,9 @@ public boolean visitToOne(ToOneProperty property) {
363362

364363
// append inheritance discriminator columns...
365364
for (ObjAttribute column : descriptor.getDiscriminatorColumns()) {
366-
if (visited.add(column.getName())) {
367-
entityResult.addDbField(column.getDbAttributePath().value(), prefix + index[0]++);
365+
String dbAttributePath = column.getDbAttributePath().value();
366+
if (visited.add(dbAttributePath)) {
367+
entityResult.addDbField(dbAttributePath, prefix + index[0]++);
368368
}
369369
}
370370

cayenne/src/main/java/org/apache/cayenne/map/DefaultEntityResultSegment.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,19 @@ public class DefaultEntityResultSegment implements EntityResultSegment {
3131
private ClassDescriptor classDescriptor;
3232
private Map<String, String> fields;
3333
private int offset;
34+
private int columnCount;
3435

3536
public DefaultEntityResultSegment(ClassDescriptor classDescriptor,
3637
Map<String, String> fields, int offset) {
38+
this(classDescriptor, fields, offset, fields != null ? fields.size() : 0);
39+
}
40+
41+
public DefaultEntityResultSegment(ClassDescriptor classDescriptor,
42+
Map<String, String> fields, int offset, int columnCount) {
3743
this.classDescriptor = classDescriptor;
3844
this.fields = fields;
3945
this.offset = offset;
46+
this.columnCount = columnCount;
4047
}
4148

4249
public ClassDescriptor getClassDescriptor() {
@@ -47,6 +54,11 @@ public Map<String, String> getFields() {
4754
return fields;
4855
}
4956

57+
@Override
58+
public int getColumnCount() {
59+
return columnCount;
60+
}
61+
5062
public int getColumnOffset() {
5163
return offset;
5264
}

cayenne/src/main/java/org/apache/cayenne/map/EntityResult.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ public Map<String, String> getDbFields(EntityResolver resolver) {
7575
return dbFields;
7676
}
7777

78+
/**
79+
* Returns the total number of fields added to this result.
80+
*/
81+
public int getFieldCount() {
82+
return fields != null ? fields.size() : 0;
83+
}
84+
7885
private ObjEntity getRootEntity(EntityResolver resolver) {
7986
if (entityName != null) {
8087
return resolver.getObjEntity(entityName);

cayenne/src/main/java/org/apache/cayenne/map/SQLResult.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,16 @@ public List<Object> getResolvedComponents(EntityResolver resolver) {
6161
} else if (component instanceof EntityResult) {
6262
EntityResult entityResult = (EntityResult) component;
6363
Map<String, String> fields = entityResult.getDbFields(resolver);
64+
int columnCount = entityResult.getFieldCount();
6465

6566
String entityName = entityResult.getEntityName();
6667
if (entityName == null) {
6768
entityName = resolver.getObjEntity(entityResult.getEntityClass()).getName();
6869
}
6970

7071
ClassDescriptor classDescriptor = resolver.getClassDescriptor(entityName);
71-
resolvedComponents.add(new DefaultEntityResultSegment(classDescriptor, fields, offset));
72-
offset = offset + fields.size();
72+
resolvedComponents.add(new DefaultEntityResultSegment(classDescriptor, fields, offset, columnCount));
73+
offset = offset + columnCount;
7374
} else if (component instanceof EmbeddedResult) {
7475
EmbeddedResult embeddedResult = (EmbeddedResult)component;
7576
Map<String, String> fields = embeddedResult.getFields();

cayenne/src/main/java/org/apache/cayenne/query/EntityResultSegment.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ public interface EntityResultSegment {
3939
*/
4040
Map<String, String> getFields();
4141

42+
/**
43+
* Returns the total number of columns in this segment.
44+
*/
45+
int getColumnCount();
46+
4247
/**
4348
* Performs a reverse lookup of the column path for a given ResultSet label.
4449
*/

cayenne/src/main/java/org/apache/cayenne/reflect/PersistentDescriptorResultMetadata.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ public String getColumnPath(String resultSetLabel) {
5252
return reverseFields.get(resultSetLabel);
5353
}
5454

55+
@Override
56+
public int getColumnCount() {
57+
return fields.size();
58+
}
59+
5560
void addObjectField(String attributeName, String column) {
5661
ObjEntity entity = classDescriptor.getEntity();
5762

cayenne/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.cayenne.ObjectContext;
2323
import org.apache.cayenne.Persistent;
2424
import org.apache.cayenne.di.Inject;
25+
import org.apache.cayenne.exp.ExpressionFactory;
2526
import org.apache.cayenne.query.ColumnSelect;
2627
import org.apache.cayenne.query.EJBQLQuery;
2728
import org.apache.cayenne.query.ObjectSelect;
@@ -727,6 +728,55 @@ public void testUpdateFlattenedRelationshipWithInverse() throws SQLException {
727728
}
728729
}
729730

731+
@Test
732+
public void testColumnQueryVerticallyInheritedToVerticallyInherited() throws SQLException {
733+
TableHelper ivDocumentTable = new TableHelper(dbHelper, "IV_DOCUMENT");
734+
ivDocumentTable.setColumns("ID", "TYPE").setColumnTypes(Types.INTEGER, Types.CHAR);
735+
736+
TableHelper ivDocumentLineTable = new TableHelper(dbHelper, "IV_DOCUMENT_LINE");
737+
ivDocumentLineTable.setColumns("ID", "TYPE", "DOCUMENT_ID").setColumnTypes(Types.INTEGER, Types.CHAR, Types.INTEGER);
738+
739+
TableHelper IvDocumentATable = new TableHelper(dbHelper, "IV_DOCUMENT_A");
740+
IvDocumentATable.setColumns("ID").setColumnTypes(Types.INTEGER);
741+
742+
TableHelper IvDocumentALineTable = new TableHelper(dbHelper, "IV_DOCUMENT_A_LINE");
743+
IvDocumentALineTable.setColumns("ID").setColumnTypes(Types.INTEGER);
744+
745+
TableHelper IvDocumentBTable = new TableHelper(dbHelper, "IV_DOCUMENT_B");
746+
IvDocumentBTable.setColumns("ID", "RELATED_A_ID").setColumnTypes(Types.INTEGER, Types.INTEGER);
747+
748+
TableHelper IvDocumentBLineTable = new TableHelper(dbHelper, "IV_DOCUMENT_B_LINE");
749+
IvDocumentBLineTable.setColumns("ID").setColumnTypes(Types.INTEGER);
750+
751+
int documentAId = 1;
752+
ivDocumentTable.insert(documentAId, "A");
753+
IvDocumentATable.insert(documentAId);
754+
755+
int documentALineId = 2;
756+
ivDocumentLineTable.insert(documentALineId, "A", documentAId);
757+
IvDocumentALineTable.insert(documentALineId);
758+
759+
int documentBId = 3;
760+
ivDocumentTable.insert(documentBId, "B");
761+
IvDocumentBTable.insert(documentBId, documentAId);
762+
763+
int documentBLineId = 4;
764+
ivDocumentLineTable.insert(documentBLineId, "B", documentBId);
765+
IvDocumentBLineTable.insert(documentBLineId);
766+
767+
{
768+
ObjectContext newContext = runtime.newContext();
769+
770+
IvDocument documentA = ObjectSelect.query(IvDocumentALine.class).where(ExpressionFactory.matchDbIdExp("ID", documentALineId)).column(IvDocumentALine.DOCUMENT).selectOne(newContext);
771+
assertNotNull(documentA);
772+
assertEquals(IvDocumentA.class, documentA.getClass());
773+
774+
IvDocument documentB = ObjectSelect.query(IvDocumentBLine.class).where(ExpressionFactory.matchDbIdExp("ID", documentBLineId)).column(IvDocumentBLine.DOCUMENT).selectOne(newContext);
775+
assertNotNull(documentB);
776+
assertEquals(IvDocumentB.class, documentB.getClass());
777+
}
778+
}
779+
730780
@Test
731781
public void testDeleteFlattenedNoValues() throws SQLException {
732782
ivAbstractTable.insert(1, null, "S");
@@ -1188,6 +1238,7 @@ public void testColumnSelectVerticalInheritance_Sub1() throws SQLException {
11881238
}
11891239

11901240
@Test
1241+
// @Ignore("Address CAY-2911")
11911242
public void testColumnSelectVerticalInheritance_Sub1Sub1() throws SQLException {
11921243
TableHelper ivRootTable = new TableHelper(dbHelper, "IV_ROOT");
11931244
ivRootTable.setColumns("ID", "NAME", "DISCRIMINATOR");
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.apache.cayenne.testdo.inheritance_vertical;
2+
3+
4+
import org.apache.cayenne.testdo.inheritance_vertical.auto._IvDocument;
5+
6+
public abstract class IvDocument extends _IvDocument {
7+
8+
private static final long serialVersionUID = 1L;
9+
10+
}

0 commit comments

Comments
 (0)