Skip to content

Commit a04f801

Browse files
committed
HHH-18860 Store SelectableMapping in ColumnWriteFragment to allow precise parameter casts
1 parent 2b5e12d commit a04f801

29 files changed

+390
-372
lines changed

hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectableConsumer.java

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
*/
55
package org.hibernate.metamodel.mapping;
66

7+
import org.checkerframework.checker.nullness.qual.Nullable;
8+
import org.hibernate.engine.jdbc.Size;
9+
710
import java.util.function.BiConsumer;
811
import java.util.function.IntFunction;
912

@@ -25,7 +28,7 @@ public interface SelectableConsumer {
2528

2629
/**
2730
* Simple form of visitation over a number of columns by name, using
28-
* a separate {@link SelectableMappings} as a base for additional details.
31+
* a separate {@link JdbcMappingContainer} as a base for additional details.
2932
* <p>
3033
* Intended for use in visiting table keys, where we know JdbcMappings, etc.
3134
* from the identifier.
@@ -44,6 +47,144 @@ default void accept(String tableName, JdbcMappingContainer base, String[] column
4447
mutableSelectableMapping.forEach( this::accept );
4548
}
4649

50+
/**
51+
* Simple form of visitation over a number of columns by name, using
52+
* a separate {@link SelectableMappings} as a base for additional details.
53+
* <p>
54+
* Intended for use in visiting table keys, where we know JdbcMappings, etc.
55+
* from the identifier.
56+
* <p>
57+
* The expectation here is for the following details to be available:<ul>
58+
* <li>{@link SelectableMapping#getContainingTableExpression()}</li>
59+
* <li>{@link SelectableMapping#getSelectionExpression()} (the column name)</li>
60+
* <li>{@link SelectableMapping#getWriteExpression()}</li>
61+
* <li>{@link SelectableMapping#getJdbcMapping()}</li>
62+
* </ul>
63+
*/
64+
default void accept(SelectableMappings base, String tableName, String[] columnNames) {
65+
class SelectableMappingIterator implements SelectableMapping {
66+
private final String tableName;
67+
private final SelectableMappings delegate;
68+
private final String[] columnNames;
69+
70+
private int index;
71+
72+
public SelectableMappingIterator(String tableName, SelectableMappings delegate, String[] columnNames) {
73+
this.tableName = tableName;
74+
this.delegate = delegate;
75+
this.columnNames = columnNames;
76+
assert delegate.getJdbcTypeCount() == columnNames.length;
77+
}
78+
79+
private void forEach(BiConsumer<Integer,SelectableMapping> consumer) {
80+
for ( index = 0; index < columnNames.length; index++ ) {
81+
consumer.accept( index, this );
82+
}
83+
}
84+
85+
@Override
86+
public String getContainingTableExpression() {
87+
return tableName;
88+
}
89+
90+
@Override
91+
public String getSelectionExpression() {
92+
return columnNames[index];
93+
}
94+
95+
@Override
96+
public @Nullable String getCustomReadExpression() {
97+
return null;
98+
}
99+
100+
@Override
101+
public @Nullable String getCustomWriteExpression() {
102+
return null;
103+
}
104+
105+
private SelectableMapping getDelegate() {
106+
return delegate.getSelectable( index );
107+
}
108+
109+
@Override
110+
public String getSelectableName() {
111+
return getDelegate().getSelectableName();
112+
}
113+
114+
@Override
115+
public SelectablePath getSelectablePath() {
116+
return getDelegate().getSelectablePath();
117+
}
118+
119+
@Override
120+
public boolean isFormula() {
121+
return getDelegate().isFormula();
122+
}
123+
124+
@Override
125+
public boolean isNullable() {
126+
return getDelegate().isNullable();
127+
}
128+
129+
@Override
130+
public boolean isInsertable() {
131+
return getDelegate().isInsertable();
132+
}
133+
134+
@Override
135+
public boolean isUpdateable() {
136+
return getDelegate().isUpdateable();
137+
}
138+
139+
@Override
140+
public boolean isPartitioned() {
141+
return getDelegate().isPartitioned();
142+
}
143+
144+
@Override
145+
public @Nullable String getColumnDefinition() {
146+
return getDelegate().getColumnDefinition();
147+
}
148+
149+
@Override
150+
public @Nullable Long getLength() {
151+
return getDelegate().getLength();
152+
}
153+
154+
@Override
155+
public @Nullable Integer getPrecision() {
156+
return getDelegate().getPrecision();
157+
}
158+
159+
@Override
160+
public @Nullable Integer getScale() {
161+
return getDelegate().getScale();
162+
}
163+
164+
@Override
165+
public @Nullable Integer getTemporalPrecision() {
166+
return getDelegate().getTemporalPrecision();
167+
}
168+
169+
@Override
170+
public boolean isLob() {
171+
return getDelegate().isLob();
172+
}
173+
174+
@Override
175+
public JdbcMapping getJdbcMapping() {
176+
return getDelegate().getJdbcMapping();
177+
}
178+
179+
@Override
180+
public Size toSize() {
181+
return getDelegate().toSize();
182+
}
183+
}
184+
185+
final SelectableMappingIterator mutableSelectableMapping = new SelectableMappingIterator( tableName, base, columnNames );
186+
mutableSelectableMapping.forEach( this::accept );
187+
}
47188

48189
class MutableSelectableMapping implements SelectableMapping {
49190
private final String tableName;

hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SelectableMappingImpl.java

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select
2525
private final String containingTableExpression;
2626
private final String selectionExpression;
2727
private final SelectablePath selectablePath;
28-
private final String customReadExpression;
29-
private final String customWriteExpression;
28+
private final @Nullable String customReadExpression;
29+
private final @Nullable String customWriteExpression;
3030
private final boolean isLob;
3131
private final boolean nullable;
3232
private final boolean insertable;
@@ -37,14 +37,14 @@ public class SelectableMappingImpl extends SqlTypedMappingImpl implements Select
3737
public SelectableMappingImpl(
3838
String containingTableExpression,
3939
String selectionExpression,
40-
SelectablePath selectablePath,
41-
String customReadExpression,
42-
String customWriteExpression,
43-
String columnDefinition,
44-
Long length,
45-
Integer precision,
46-
Integer scale,
47-
Integer temporalPrecision,
40+
@Nullable SelectablePath selectablePath,
41+
@Nullable String customReadExpression,
42+
@Nullable String customWriteExpression,
43+
@Nullable String columnDefinition,
44+
@Nullable Long length,
45+
@Nullable Integer precision,
46+
@Nullable Integer scale,
47+
@Nullable Integer temporalPrecision,
4848
boolean isLob,
4949
boolean nullable,
5050
boolean insertable,
@@ -55,7 +55,7 @@ public SelectableMappingImpl(
5555
super( columnDefinition, length, precision, scale, temporalPrecision, jdbcMapping );
5656
assert selectionExpression != null;
5757
// Save memory by using interned strings. Probability is high that we have multiple duplicate strings
58-
this.containingTableExpression = containingTableExpression == null ? null : containingTableExpression.intern();
58+
this.containingTableExpression = containingTableExpression.intern();
5959
this.selectionExpression = selectionExpression.intern();
6060
this.selectablePath = selectablePath == null ? new SelectablePath( selectionExpression ) : selectablePath;
6161
this.customReadExpression = customReadExpression == null ? null : customReadExpression.intern();
@@ -241,7 +241,7 @@ public String getSelectionExpression() {
241241

242242
@Override
243243
public String getSelectableName() {
244-
return selectablePath == null ? null : selectablePath.getSelectableName();
244+
return selectablePath.getSelectableName();
245245
}
246246

247247
@Override
@@ -250,17 +250,12 @@ public SelectablePath getSelectablePath() {
250250
}
251251

252252
@Override
253-
public String getCustomReadExpression() {
253+
public @Nullable String getCustomReadExpression() {
254254
return customReadExpression;
255255
}
256256

257257
@Override
258-
public String getCustomWriteExpression() {
259-
return customWriteExpression;
260-
}
261-
262-
@Override
263-
public String getWriteExpression() {
258+
public @Nullable String getCustomWriteExpression() {
264259
return customWriteExpression;
265260
}
266261

hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SoftDeleteMappingImpl.java

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -214,41 +214,19 @@ public Predicate createNonDeletedRestriction(TableReference tableReference, SqlE
214214

215215
@Override
216216
public ColumnValueBinding createNonDeletedValueBinding(ColumnReference softDeleteColumnReference) {
217-
final ColumnWriteFragment nonDeletedFragment;
218-
if ( strategy == SoftDeleteType.TIMESTAMP ) {
219-
nonDeletedFragment = new ColumnWriteFragment(
220-
null,
221-
Collections.emptyList(),
222-
jdbcMapping
223-
);
224-
}
225-
else {
226-
nonDeletedFragment = new ColumnWriteFragment(
227-
nonDeletedLiteralText,
228-
Collections.emptyList(),
229-
jdbcMapping
230-
);
231-
}
217+
final var nonDeletedFragment =
218+
strategy == SoftDeleteType.TIMESTAMP
219+
? new ColumnWriteFragment( null, Collections.emptyList(), this )
220+
: new ColumnWriteFragment( nonDeletedLiteralText, Collections.emptyList(), this );
232221
return new ColumnValueBinding( softDeleteColumnReference, nonDeletedFragment );
233222
}
234223

235224
@Override
236225
public ColumnValueBinding createDeletedValueBinding(ColumnReference softDeleteColumnReference) {
237-
final ColumnWriteFragment deletedFragment;
238-
if ( strategy == SoftDeleteType.TIMESTAMP ) {
239-
deletedFragment = new ColumnWriteFragment(
240-
currentTimestampFunctionName,
241-
Collections.emptyList(),
242-
getJdbcMapping()
243-
);
244-
}
245-
else {
246-
deletedFragment = new ColumnWriteFragment(
247-
deletedLiteralText,
248-
Collections.emptyList(),
249-
jdbcMapping
250-
);
251-
}
226+
final ColumnWriteFragment deletedFragment =
227+
strategy == SoftDeleteType.TIMESTAMP
228+
? new ColumnWriteFragment( currentTimestampFunctionName, Collections.emptyList(), this )
229+
: new ColumnWriteFragment( deletedLiteralText, Collections.emptyList(), this );
252230
return new ColumnValueBinding( softDeleteColumnReference, deletedFragment );
253231
}
254232

hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@
9898
import org.hibernate.sql.ast.spi.SqlAstCreationState;
9999
import org.hibernate.sql.ast.spi.SqlSelection;
100100
import org.hibernate.sql.ast.tree.expression.AliasedExpression;
101-
import org.hibernate.sql.ast.tree.expression.ColumnReference;
102101
import org.hibernate.sql.ast.tree.from.TableGroup;
103102
import org.hibernate.sql.ast.tree.from.TableReference;
104103
import org.hibernate.sql.ast.tree.predicate.Predicate;
@@ -109,7 +108,6 @@
109108
import org.hibernate.sql.model.TableMapping;
110109
import org.hibernate.sql.model.TableMapping.MutationDetails;
111110
import org.hibernate.sql.model.ast.ColumnValueBinding;
112-
import org.hibernate.sql.model.ast.ColumnValueParameter;
113111
import org.hibernate.sql.model.ast.ColumnValueParameterList;
114112
import org.hibernate.sql.model.ast.ColumnWriteFragment;
115113
import org.hibernate.sql.model.ast.MutatingTableReference;
@@ -134,6 +132,7 @@
134132
import java.util.HashMap;
135133
import java.util.HashSet;
136134
import java.util.Iterator;
135+
import java.util.List;
137136
import java.util.Locale;
138137
import java.util.Map;
139138
import java.util.Set;
@@ -1753,7 +1752,7 @@ public RestrictedTableMutation<JdbcMutationOperation> generateDeleteAllAst(Mutat
17531752
final ColumnValueParameterList parameterBinders =
17541753
new ColumnValueParameterList( tableReference, ParameterUsage.RESTRICT, keyColumnCount );
17551754
final java.util.List<ColumnValueBinding> restrictionBindings = arrayList( keyColumnCount );
1756-
applyKeyRestrictions( tableReference, parameterBinders, restrictionBindings );
1755+
applyKeyRestrictions( parameterBinders, restrictionBindings );
17571756

17581757
//noinspection unchecked,rawtypes
17591758
return (RestrictedTableMutation) new TableDeleteStandard(
@@ -1768,27 +1767,24 @@ public RestrictedTableMutation<JdbcMutationOperation> generateDeleteAllAst(Mutat
17681767
}
17691768

17701769
protected void applyKeyRestrictions(
1771-
MutatingTableReference tableReference,
17721770
ColumnValueParameterList parameterList,
1773-
java.util.List<ColumnValueBinding> restrictionBindings) {
1774-
1775-
final ForeignKeyDescriptor fkDescriptor = getAttributeMapping().getKeyDescriptor();
1776-
assert fkDescriptor != null;
1777-
1778-
fkDescriptor.getKeyPart().forEachSelectable( parameterList );
1779-
for ( ColumnValueParameter columnValueParameter : parameterList ) {
1780-
final ColumnReference columnReference = columnValueParameter.getColumnReference();
1771+
List<ColumnValueBinding> restrictionBindings) {
1772+
final var foreignKeyDescriptor = getAttributeMapping().getKeyDescriptor();
1773+
assert foreignKeyDescriptor != null;
1774+
foreignKeyDescriptor.getKeyPart().forEachSelectable( (selectionIndex, selectableMapping) -> {
1775+
final var columnValueParameter = parameterList.addColumValueParameter( selectableMapping );
1776+
final var columnReference = columnValueParameter.getColumnReference();
17811777
restrictionBindings.add(
17821778
new ColumnValueBinding(
17831779
columnReference,
17841780
new ColumnWriteFragment(
17851781
"?",
17861782
columnValueParameter,
1787-
columnReference.getJdbcMapping()
1783+
selectableMapping
17881784
)
17891785
)
17901786
);
1791-
}
1787+
});
17921788
}
17931789

17941790

hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ public RestrictedTableMutation<JdbcMutationOperation> generateDeleteAllAst(Mutat
217217
keyColumnCount
218218
);
219219
final java.util.List<ColumnValueBinding> restrictionBindings = arrayList( keyColumnCount );
220-
applyKeyRestrictions( tableReference, parameterBinders, restrictionBindings );
220+
applyKeyRestrictions( parameterBinders, restrictionBindings );
221221

222222
final ColumnReference softDeleteColumn = new ColumnReference( tableReference, softDeleteMapping );
223223
final ColumnValueBinding nonDeletedBinding = softDeleteMapping.createNonDeletedValueBinding( softDeleteColumn );

0 commit comments

Comments
 (0)