7070import org .hibernate .sql .ast .SqlAstNodeRenderingMode ;
7171import org .hibernate .sql .ast .SqlAstTranslator ;
7272import org .hibernate .sql .ast .SqlTreeCreationException ;
73- import org .hibernate .sql .ast .internal .ParameterMarkerStrategyStandard ;
7473import org .hibernate .sql .ast .internal .TableGroupHelper ;
74+ import org .hibernate .sql .ast .internal .ParameterMarkerStrategyStandard ;
7575import org .hibernate .sql .ast .tree .AbstractUpdateOrDeleteStatement ;
7676import org .hibernate .sql .ast .tree .MutationStatement ;
7777import org .hibernate .sql .ast .tree .SqlAstNode ;
135135import org .hibernate .sql .exec .internal .AbstractJdbcParameter ;
136136import org .hibernate .sql .exec .internal .JdbcOperationQueryInsertImpl ;
137137import org .hibernate .sql .exec .internal .JdbcParameterBindingImpl ;
138- import org .hibernate .sql .exec .internal .JdbcParametersImpl ;
139138import org .hibernate .sql .exec .internal .SqlTypedMappingJdbcParameter ;
140139import org .hibernate .sql .exec .spi .ExecutionContext ;
141140import org .hibernate .sql .exec .spi .JdbcLockStrategy ;
177176import java .sql .SQLException ;
178177import java .time .Period ;
179178import java .util .ArrayList ;
179+ import java .util .Arrays ;
180180import java .util .BitSet ;
181181import java .util .Collection ;
182182import java .util .Collections ;
@@ -260,7 +260,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
260260 private final StringBuilder sqlBuffer = new StringBuilder ();
261261
262262 private final List <JdbcParameterBinder > parameterBinders = new ArrayList <>();
263- private final JdbcParametersImpl jdbcParameters = new JdbcParametersImpl () ;
263+ private int [] parameterIdToBinderIndex ;
264264 private JdbcParameterBindings jdbcParameterBindings ;
265265 private Map <JdbcParameter , JdbcParameterBinding > appliedParameterBindings = Collections .emptyMap ();
266266 private SqlAstNodeRenderingMode parameterRenderingMode = SqlAstNodeRenderingMode .DEFAULT ;
@@ -4607,11 +4607,10 @@ protected void renderFetchPlusOffsetExpressionAsSingleParameter(
46074607 appendSql ( fetchCount .intValue () + offsetCount .intValue () + offset );
46084608 }
46094609 else {
4610- appendSql ( PARAM_MARKER );
46114610 final JdbcParameter offsetParameter = (JdbcParameter ) offsetClauseExpression ;
46124611 final int offsetValue = offset + fetchCount .intValue ();
4613- jdbcParameters . addParameter ( offsetParameter );
4614- parameterBinders . add (
4612+ final int parameterPosition = addParameterBinder (
4613+ offsetParameter ,
46154614 (statement , startPosition , jdbcParameterBindings , executionContext ) -> {
46164615 final JdbcParameterBinding binding = jdbcParameterBindings .getBinding ( offsetParameter );
46174616 if ( binding == null ) {
@@ -4627,44 +4626,29 @@ protected void renderFetchPlusOffsetExpressionAsSingleParameter(
46274626 );
46284627 }
46294628 );
4629+ renderParameterAsParameter ( parameterPosition , offsetParameter );
46304630 }
46314631 }
46324632 else {
4633- appendSql ( PARAM_MARKER );
46344633 final JdbcParameter offsetParameter = (JdbcParameter ) offsetClauseExpression ;
46354634 final JdbcParameter fetchParameter = (JdbcParameter ) fetchClauseExpression ;
4636- final OffsetReceivingParameterBinder fetchBinder = new OffsetReceivingParameterBinder (
4635+ final FetchPlusOffsetParameterBinder fetchBinder = new FetchPlusOffsetParameterBinder (
46374636 offsetParameter ,
46384637 fetchParameter ,
46394638 offset
46404639 );
4641- // We don't register and bind the special OffsetJdbcParameter as that comes from the query options
4642- // And in this case, we only want to bind a single JDBC parameter
4643- if ( !( offsetParameter instanceof OffsetJdbcParameter ) ) {
4644- jdbcParameters .addParameter ( offsetParameter );
4645- parameterBinders .add (
4646- (statement , startPosition , jdbcParameterBindings , executionContext ) -> {
4647- final JdbcParameterBinding binding = jdbcParameterBindings .getBinding ( offsetParameter );
4648- if ( binding == null ) {
4649- throw new ExecutionException ( "JDBC parameter value not bound - " + offsetParameter );
4650- }
4651- fetchBinder .dynamicOffset = (Number ) binding .getBindValue ();
4652- }
4653- );
4654- }
4655- jdbcParameters .addParameter ( fetchParameter );
4656- parameterBinders .add ( fetchBinder );
4640+ final int parameterPosition = addParameterBinder ( fetchParameter , fetchBinder );
4641+ renderParameterAsParameter ( parameterPosition , fetchParameter );
46574642 }
46584643 }
46594644
4660- private static class OffsetReceivingParameterBinder implements JdbcParameterBinder {
4645+ private static class FetchPlusOffsetParameterBinder implements JdbcParameterBinder {
46614646
46624647 private final JdbcParameter offsetParameter ;
46634648 private final JdbcParameter fetchParameter ;
46644649 private final int staticOffset ;
4665- private Number dynamicOffset ;
46664650
4667- public OffsetReceivingParameterBinder (
4651+ public FetchPlusOffsetParameterBinder (
46684652 JdbcParameter offsetParameter ,
46694653 JdbcParameter fetchParameter ,
46704654 int staticOffset ) {
@@ -4695,8 +4679,11 @@ public void bindParameterValue(
46954679 offsetValue = executionContext .getQueryOptions ().getEffectiveLimit ().getFirstRow ();
46964680 }
46974681 else {
4698- offsetValue = dynamicOffset .intValue () + staticOffset ;
4699- dynamicOffset = null ;
4682+ final JdbcParameterBinding binding = jdbcParameterBindings .getBinding ( offsetParameter );
4683+ if ( binding == null ) {
4684+ throw new ExecutionException ( "JDBC parameter value not bound - " + offsetParameter );
4685+ }
4686+ offsetValue = ((Number ) binding .getBindValue ()).intValue () + staticOffset ;
47004687 }
47014688 //noinspection unchecked
47024689 fetchParameter .getExpressionType ().getSingleJdbcMapping ().getJdbcValueBinder ().bind (
@@ -5670,15 +5657,15 @@ protected void renderLiteral(Literal literal, boolean castParameter) {
56705657 final JdbcLiteralFormatter <Object > literalFormatter = literal .getJdbcMapping ().getJdbcLiteralFormatter ();
56715658 // If we encounter a plain literal in the select clause which has no literal formatter, we must render it as parameter
56725659 if ( literalFormatter == null ) {
5673- parameterBinders . add ( literal );
5660+ final int parameterPosition = addParameterBinderOnly ( literal );
56745661 final JdbcType jdbcType = literal .getJdbcMapping ().getJdbcType ();
5675- final String marker = parameterMarkerStrategy .createMarker ( parameterBinders . size () , jdbcType );
5676- final LiteralAsParameter <?> jdbcParameter = new LiteralAsParameter <>( literal , marker );
5662+ final String marker = parameterMarkerStrategy .createMarker ( parameterPosition , jdbcType );
5663+
56775664 if ( castParameter ) {
5678- renderCasted ( jdbcParameter );
5665+ renderCasted ( new LiteralAsParameter <>( literal , marker ) );
56795666 }
56805667 else {
5681- jdbcParameter . renderToSql ( this , this , sessionFactory );
5668+ jdbcType . appendWriteExpression ( marker , this , dialect );
56825669 }
56835670 }
56845671 else {
@@ -7002,15 +6989,8 @@ public void visitParameter(JdbcParameter jdbcParameter) {
70026989 }
70036990
70046991 protected void visitParameterAsParameter (JdbcParameter jdbcParameter ) {
7005- renderParameterAsParameter ( jdbcParameter );
7006- parameterBinders .add ( jdbcParameter .getParameterBinder () );
7007- jdbcParameters .addParameter ( jdbcParameter );
7008- }
7009-
7010- protected final void renderParameterAsParameter (JdbcParameter jdbcParameter ) {
7011- final JdbcType jdbcType = jdbcParameter .getExpressionType ().getJdbcMapping ( 0 ).getJdbcType ();
7012- assert jdbcType != null ;
7013- renderParameterAsParameter ( parameterBinders .size () + 1 , jdbcParameter );
6992+ final int parameterPosition = addParameterBinder ( jdbcParameter );
6993+ renderParameterAsParameter ( parameterPosition , jdbcParameter );
70146994 }
70156995
70166996 protected void renderWrappedParameter (JdbcParameter jdbcParameter ) {
@@ -7037,6 +7017,53 @@ protected void renderParameterAsParameter(int position, JdbcParameter jdbcParame
70377017 jdbcType .appendWriteExpression ( parameterMarker , this , dialect );
70387018 }
70397019
7020+ protected final int addParameterBinder (JdbcParameter parameter ) {
7021+ return addParameterBinder ( parameter , parameter .getParameterBinder () );
7022+ }
7023+
7024+ protected final int addParameterBinder (JdbcParameter parameter , JdbcParameterBinder parameterBinder ) {
7025+ final Integer parameterId = parameter .getParameterId ();
7026+ if ( ParameterMarkerStrategyStandard .isStandardRenderer ( parameterMarkerStrategy )
7027+ // Filter parameters are unique and they are not tracked via parameterInfo
7028+ || parameter instanceof FilterJdbcParameter
7029+ || parameterId == null ) {
7030+ return addParameterBinderOnly ( parameterBinder );
7031+ }
7032+ else {
7033+ parameterIdToBinderIndex = ensureCapacity ( parameterIdToBinderIndex , parameterId + 1 );
7034+ int binderIndex = parameterIdToBinderIndex [parameterId ];
7035+ if ( binderIndex == -1 ) {
7036+ parameterIdToBinderIndex [parameterId ] = binderIndex = addParameterBinderOnly ( parameterBinder );
7037+ }
7038+ return binderIndex ;
7039+ }
7040+ }
7041+
7042+ private static int [] ensureCapacity (int [] array , int minCapacity ) {
7043+ int oldCapacity ;
7044+ if ( array == null ) {
7045+ oldCapacity = 0 ;
7046+ array = new int [minCapacity ];
7047+ }
7048+ else {
7049+ oldCapacity = array .length ;
7050+ if ( minCapacity > oldCapacity ) {
7051+ int newCapacity = oldCapacity + (oldCapacity >> 1 );
7052+ newCapacity = Math .max ( Math .max ( newCapacity , minCapacity ), 10 );
7053+ array = Arrays .copyOf ( array , newCapacity );
7054+ }
7055+ }
7056+ for ( int i = oldCapacity ; i < array .length ; i ++ ) {
7057+ array [i ] = -1 ;
7058+ }
7059+ return array ;
7060+ }
7061+
7062+ private int addParameterBinderOnly (JdbcParameterBinder parameterBinder ) {
7063+ parameterBinders .add ( parameterBinder );
7064+ return parameterBinders .size ();
7065+ }
7066+
70407067 @ Override
70417068 public void render (SqlAstNode sqlAstNode , SqlAstNodeRenderingMode renderingMode ) {
70427069 final SqlAstNodeRenderingMode original = this .parameterRenderingMode ;
@@ -8495,7 +8522,7 @@ public void visitCustomTableInsert(TableInsertCustomSql tableInsert) {
84958522 assert sqlBuffer .toString ().isEmpty ();
84968523 sqlBuffer .append ( tableInsert .getCustomSql () );
84978524
8498- tableInsert .forEachParameter ( this ::applyParameter );
8525+ tableInsert .forEachParameter ( this ::addParameterBinder );
84998526 }
85008527
85018528 @ Override
@@ -8604,7 +8631,7 @@ public void visitCustomTableUpdate(TableUpdateCustomSql tableUpdate) {
86048631 assert sqlBuffer .toString ().isEmpty ();
86058632 sqlBuffer .append ( tableUpdate .getCustomSql () );
86068633
8607- tableUpdate .forEachParameter ( this ::applyParameter );
8634+ tableUpdate .forEachParameter ( this ::addParameterBinder );
86088635 }
86098636
86108637 @ Override
@@ -8668,13 +8695,7 @@ public void visitCustomTableDelete(TableDeleteCustomSql tableDelete) {
86688695 assert sqlBuffer .toString ().isEmpty ();
86698696 sqlBuffer .append ( tableDelete .getCustomSql () );
86708697
8671- tableDelete .forEachParameter ( this ::applyParameter );
8672- }
8673-
8674- protected void applyParameter (ColumnValueParameter parameter ) {
8675- assert parameter != null ;
8676- parameterBinders .add ( parameter .getParameterBinder () );
8677- jdbcParameters .addParameter ( parameter );
8698+ tableDelete .forEachParameter ( this ::addParameterBinder );
86788699 }
86798700
86808701 @ Override
@@ -8711,10 +8732,6 @@ public void visitColumnWriteFragment(ColumnWriteFragment columnWriteFragment) {
87118732
87128733 protected void simpleColumnWriteFragmentRendering (ColumnWriteFragment columnWriteFragment ) {
87138734 appendSql ( columnWriteFragment .getFragment () );
8714-
8715- for ( ColumnValueParameter parameter : columnWriteFragment .getParameters () ) {
8716- parameterBinders .add ( parameter .getParameterBinder () );
8717- jdbcParameters .addParameter ( parameter );
8718- }
8735+ columnWriteFragment .getParameters ().forEach ( this ::addParameterBinder );
87198736 }
87208737}
0 commit comments