2020
2121import org .apache .cayenne .CayenneRuntimeException ;
2222import org .apache .cayenne .access .jdbc .RSColumn ;
23- import org .apache .cayenne .access .types .ExtendedType ;
2423import org .apache .cayenne .dba .DbAdapter ;
2524import org .apache .cayenne .map .DbAttribute ;
2625import org .apache .cayenne .map .DbEntity ;
3029import org .apache .cayenne .query .QueryMetadata ;
3130import org .apache .cayenne .query .ScalarResultSegment ;
3231
32+ import java .util .Arrays ;
3333import java .util .List ;
3434
3535/**
3838public class DefaultRowReaderFactory implements RowReaderFactory {
3939
4040 @ Override
41- public RowReader <?> rowReader (RSColumn [] columns , QueryMetadata queryMetadata , DbAdapter adapter ) {
41+ public RowReader <?> rowReader (RSColumn [] columns , QueryMetadata metadata , DbAdapter adapter ) {
4242
43- List <Object > segments = queryMetadata .getResultSetMapping ();
43+ List <Object > segments = metadata .getResultSetMapping ();
4444 if (segments == null || segments .isEmpty ()) {
45- return createFullRowReader (columns , queryMetadata );
45+ return fullRowReader (columns , metadata );
4646 }
4747
48- if (queryMetadata .isSingleResultSetMapping ()) {
49- return segmentRowReader (segments .getFirst (), columns , queryMetadata );
48+ if (metadata .isSingleResultSetMapping ()) {
49+ return segmentRowReader (segments .getFirst (), columns , metadata );
5050 }
5151
5252 int w = segments .size ();
5353 RowReader <?>[] readers = new RowReader [w ];
5454 for (int i = 0 ; i < w ; i ++) {
55- readers [i ] = segmentRowReader (segments .get (i ), columns , queryMetadata );
55+ readers [i ] = segmentRowReader (segments .get (i ), columns , metadata );
5656 }
5757
5858 return new CompoundRowReader (readers );
5959 }
6060
61- private RowReader <?> segmentRowReader (Object segment , RSColumn [] columns , QueryMetadata queryMetadata ) {
61+ private RowReader <?> segmentRowReader (Object segment , RSColumn [] columns , QueryMetadata metadata ) {
6262 return switch (segment ) {
63- case EntityResultSegment ers -> createEntityRowReader (columns , queryMetadata , ers );
64- case EmbeddableResultSegment ers -> createEmbeddableRowReader (columns , ers );
65- case ScalarResultSegment srs -> createScalarRowReader (columns , queryMetadata , srs );
63+ case EntityResultSegment ers -> entitySegmentReader (columns , metadata , ers );
64+ case EmbeddableResultSegment ers -> embeddableSegmentReader (columns , ers );
65+ case ScalarResultSegment srs -> scalarSegmentReader (columns , metadata , srs );
6666 case null , default -> throw new IllegalStateException ("Unknown segment type: " + segment );
6767 };
6868 }
6969
70- private RowReader <?> createEmbeddableRowReader (RSColumn [] columns , EmbeddableResultSegment segment ) {
71- int segmentWidth = segment .getFields ().size ();
70+ private RowReader <?> embeddableSegmentReader (RSColumn [] columns , EmbeddableResultSegment segment ) {
7271 int startIndex = segment .getColumnOffset ();
73- ExtendedType <?>[] converters = new ExtendedType [segmentWidth ];
74- int [] types = new int [segmentWidth ];
75- String [] labels = new String [segmentWidth ];
72+ int segmentWidth = segment .getFields ().size ();
73+
74+ // recast the segment's columns into a compact array so their dataRowName carries the embeddable field
75+ // label (keyed by the result-set column name); OffsetRowReader reads them from startIndex onward
76+ RSColumn [] relabeled = new RSColumn [segmentWidth ];
7677
7778 for (int i = 0 ; i < segmentWidth ; i ++) {
78- converters [i ] = columns [startIndex + i ].reader ();
79- types [i ] = columns [startIndex + i ].rsType ();
80- labels [i ] = segment .getFields ().get (columns [startIndex + i ].rsName ());
79+ RSColumn column = columns [startIndex + i ];
80+ relabeled [i ] = new RSColumn (
81+ column .rsName (),
82+ column .rsType (),
83+ segment .getFields ().get (column .rsName ()),
84+ column .reader (),
85+ column .attribute ());
8186 }
8287
83- return new EmbeddableRowReader (converters , types , labels , startIndex );
88+ // an embeddable segment carries no entity - no entity name, no inheritance
89+ return OffsetRowReader .of (relabeled , startIndex );
8490 }
8591
86- protected RowReader <?> createScalarRowReader (RSColumn [] columns , QueryMetadata queryMetadata , ScalarResultSegment segment ) {
92+ protected RowReader <?> scalarSegmentReader (RSColumn [] columns , QueryMetadata metadata , ScalarResultSegment segment ) {
8793 int scalarIndex = segment .getColumnOffset ();
8894 return new ScalarRowReader <>(
8995 columns [scalarIndex ].reader (),
@@ -92,51 +98,50 @@ protected RowReader<?> createScalarRowReader(RSColumn[] columns, QueryMetadata q
9298 columns [scalarIndex ].rsType ());
9399 }
94100
95- protected RowReader <?> createEntityRowReader (
96- RSColumn [] columns ,
97- QueryMetadata queryMetadata ,
98- EntityResultSegment resultMetadata ) {
101+ protected RowReader <?> entitySegmentReader (RSColumn [] columns , QueryMetadata metadata , EntityResultSegment segment ) {
99102
100- if (queryMetadata .getPageSize () > 0 ) {
101- return createIdRowReader (columns , queryMetadata , resultMetadata );
103+ if (metadata .getPageSize () > 0 ) {
104+ return idReader (columns , metadata , segment );
102105 }
103106
104- int startIndex = resultMetadata .getColumnOffset ();
105- int segmentWidth = resultMetadata .getFields ().size ();
106- ExtendedType <?>[] readers = new ExtendedType [segmentWidth ];
107- int [] types = new int [segmentWidth ];
108- String [] labels = new String [segmentWidth ];
107+ int startIndex = segment .getColumnOffset ();
108+ int segmentWidth = segment .getFields ().size ();
109+
110+ // recast the segment's columns into a compact array so their dataRowName carries the resolved DataRow
111+ // label (which is how the reader keys the DataRow); OffsetRowReader reads them from startIndex onward
112+ RSColumn [] relabeled = new RSColumn [segmentWidth ];
109113
110114 for (int i = 0 ; i < segmentWidth ; i ++) {
111115 RSColumn column = columns [startIndex + i ];
112- readers [i ] = column .reader ();
113- types [i ] = column .rsType ();
114116
115117 // the query translator may reorder fields compared to the entity result, so resolve the
116- // DataRow label by reverse lookup of the column name...
117- if (column .dataRowName ().contains ("." )) {
118- // a dotted dataRowName is a prefetched column - use it directly instead of by alias
119- labels [i ] = column .dataRowName ();
120- } else {
121- labels [i ] = resultMetadata .getColumnPath (column .dataRowName ());
122- }
118+ // DataRow label by reverse lookup of the column name; a dotted dataRowName is a prefetched
119+ // column, used directly instead of by alias
120+ String name = column .dataRowName ();
121+ String label = name .contains ("." ) ? name : segment .getColumnPath (name );
122+
123+ relabeled [i ] = new RSColumn (
124+ column .rsName (),
125+ column .rsType (),
126+ label ,
127+ column .reader (),
128+ column .attribute ());
123129 }
124130
125- return EntityRowReader .of (readers , types , labels , startIndex , resultMetadata .getClassDescriptor ());
131+ return OffsetRowReader .of (relabeled , startIndex , segment .getClassDescriptor ());
126132 }
127133
128- protected RowReader <?> createFullRowReader (RSColumn [] columns , QueryMetadata queryMetadata ) {
134+ protected RowReader <?> fullRowReader (RSColumn [] columns , QueryMetadata metadata ) {
129135
130- if (queryMetadata .getPageSize () > 0 ) {
131- return createIdRowReader (columns , queryMetadata , null );
136+ if (metadata .getPageSize () > 0 ) {
137+ return idReader (columns , metadata , null );
132138 }
133139
134- return FullRowReader .of (columns , queryMetadata );
140+ return FullRowReader .of (columns , metadata );
135141 }
136142
137- private RowReader <?> createIdRowReader (RSColumn [] columns , QueryMetadata queryMetadata ,
138- EntityResultSegment resultMetadata ) {
139- int [] pk = pkIndices (columns , queryMetadata , resultMetadata );
143+ private RowReader <?> idReader (RSColumn [] columns , QueryMetadata metadata , EntityResultSegment segment ) {
144+ int [] pk = pkIndices (columns , metadata , segment );
140145
141146 // single-column PK - read the value directly as a scalar
142147 if (pk .length == 1 ) {
@@ -145,18 +150,17 @@ private RowReader<?> createIdRowReader(RSColumn[] columns, QueryMetadata queryMe
145150 return new ScalarRowReader <>(column .reader (), pk [0 ] + 1 , column .rsType ());
146151 }
147152
148- return new IndexedRowReader ( columns , entityName ( queryMetadata ), pk );
149- }
153+ // a multi-column PK occupies a contiguous run starting at pk[0] - read it as a compact segment
154+ RSColumn [] pkColumns = Arrays . copyOfRange ( columns , pk [ 0 ], pk [ 0 ] + pk . length );
150155
151- private static String entityName (QueryMetadata queryMetadata ) {
152- ObjEntity objEntity = queryMetadata .getObjEntity ();
153- return objEntity != null ? objEntity .getName () : null ;
156+ ObjEntity objEntity = metadata .getObjEntity ();
157+ return OffsetRowReader .of (pkColumns , pk [0 ], objEntity != null ? objEntity .getName () : null );
154158 }
155159
156- private static int [] pkIndices (RSColumn [] columns , QueryMetadata queryMetadata , EntityResultSegment resultMetadata ) {
157- DbEntity dbEntity = resultMetadata == null
158- ? queryMetadata .getDbEntity ()
159- : resultMetadata .getClassDescriptor ().getEntity ().getDbEntity ();
160+ private static int [] pkIndices (RSColumn [] columns , QueryMetadata metadata , EntityResultSegment segment ) {
161+ DbEntity dbEntity = segment == null
162+ ? metadata .getDbEntity ()
163+ : segment .getClassDescriptor ().getEntity ().getDbEntity ();
160164 if (dbEntity == null ) {
161165 throw new CayenneRuntimeException ("Null root DbEntity, can't index PK" );
162166 }
@@ -167,7 +171,7 @@ private static int[] pkIndices(RSColumn[] columns, QueryMetadata queryMetadata,
167171 }
168172
169173 int [] pk = new int [len ];
170- int offset = resultMetadata != null ? resultMetadata .getColumnOffset () : 0 ;
174+ int offset = segment != null ? segment .getColumnOffset () : 0 ;
171175 for (int i = offset , j = 0 ; i < offset + len ; i ++) {
172176 DbAttribute a = dbEntity .getAttribute (columns [i ].rsName ());
173177 if (a != null && a .isPrimaryKey ()) {
0 commit comments