88
88
import org .hibernate .query .sql .spi .ParameterInterpretation ;
89
89
import org .hibernate .query .sql .spi .ParameterOccurrence ;
90
90
import org .hibernate .query .sql .spi .SelectInterpretationsKey ;
91
+ import org .hibernate .sql .ast .spi .ParameterMarkerStrategy ;
91
92
import org .hibernate .sql .exec .internal .CallbackImpl ;
92
93
import org .hibernate .sql .exec .spi .Callback ;
93
94
import org .hibernate .sql .results .jdbc .spi .JdbcValuesMappingProducer ;
@@ -368,7 +369,8 @@ private ParameterInterpretation resolveParameterInterpretation(
368
369
return interpretationCache .resolveNativeQueryParameters (
369
370
sqlString ,
370
371
s -> {
371
- final ParameterRecognizerImpl parameterRecognizer = new ParameterRecognizerImpl ();
372
+ final ParameterMarkerStrategy parameterMarkerStrategy = sessionFactory .getServiceRegistry ().getService ( ParameterMarkerStrategy .class );
373
+ final ParameterRecognizerImpl parameterRecognizer = new ParameterRecognizerImpl ( parameterMarkerStrategy );
372
374
373
375
session .getFactory ().getServiceRegistry ()
374
376
.requireService ( NativeQueryInterpreter .class )
@@ -734,23 +736,36 @@ protected String expandParameterLists() {
734
736
// Some DBs limit number of IN expressions. For now, warn...
735
737
final SessionFactoryImplementor sessionFactory = getSessionFactory ();
736
738
final Dialect dialect = sessionFactory .getJdbcServices ().getDialect ();
739
+
740
+ final ParameterMarkerStrategy parameterMarkerStrategy = sessionFactory .getServiceRegistry ().getService ( ParameterMarkerStrategy .class );
741
+
737
742
final boolean paddingEnabled = sessionFactory .getSessionFactoryOptions ().inClauseParameterPaddingEnabled ();
738
743
final int inExprLimit = dialect .getInExpressionCountLimit ();
739
744
740
745
StringBuilder sb = null ;
746
+ StringBuilder occurrenceExpansionSB = null ;
741
747
742
748
// Handle parameter lists
743
- int offset = 0 ;
744
- for ( ParameterOccurrence occurrence : parameterOccurrences ) {
749
+ int sourceOffset = 0 ;
750
+ int expandedParamPosition = 1 ;
751
+ for ( int originalParamPosition = 1 ; originalParamPosition <= parameterOccurrences .size (); originalParamPosition ++ ) {
752
+ final ParameterOccurrence occurrence = parameterOccurrences .get ( originalParamPosition - 1 );
745
753
final QueryParameterImplementor <?> queryParameter = occurrence .getParameter ();
746
754
final QueryParameterBinding <?> binding = parameterBindings .getBinding ( queryParameter );
747
755
if ( !binding .isMultiValued () ) {
756
+ if ( originalParamPosition != expandedParamPosition ) {
757
+ if ( sb == null ) {
758
+ sb = new StringBuilder ( sqlString );
759
+ }
760
+ sourceOffset = getNewSourceOffsetAfterReplacement ( sb , sourceOffset , occurrence , parameterMarkerStrategy .createMarker ( expandedParamPosition , null ) );
761
+ }
762
+ expandedParamPosition ++;
748
763
continue ;
749
764
}
750
765
final Collection <?> bindValues = binding .getBindValues ();
751
766
752
- int bindValueCount = bindValues .size ();
753
- int bindValueMaxCount = determineBindValueMaxCount ( paddingEnabled , inExprLimit , bindValueCount );
767
+ final int bindValueCount = bindValues .size ();
768
+ final int bindValueMaxCount = determineBindValueMaxCount ( paddingEnabled , inExprLimit , bindValueCount );
754
769
755
770
if ( inExprLimit > 0 && bindValueCount > inExprLimit ) {
756
771
log .tooManyInExpressions (
@@ -765,6 +780,7 @@ protected String expandParameterLists() {
765
780
766
781
final int sourcePosition = occurrence .getSourcePosition ();
767
782
if ( sourcePosition < 0 ) {
783
+ expandedParamPosition ++;
768
784
continue ;
769
785
}
770
786
@@ -779,7 +795,7 @@ protected String expandParameterLists() {
779
795
}
780
796
}
781
797
if ( isEnclosedInParens ) {
782
- for ( int i = sourcePosition + 1 ; i < sqlString .length (); i ++ ) {
798
+ for ( int i = sourcePosition + occurrence . getLength () ; i < sqlString .length (); i ++ ) {
783
799
final char ch = sqlString .charAt ( i );
784
800
if ( !Character .isWhitespace ( ch ) ) {
785
801
isEnclosedInParens = ch == ')' ;
@@ -788,62 +804,62 @@ protected String expandParameterLists() {
788
804
}
789
805
}
790
806
791
- if ( bindValueCount == 1 && isEnclosedInParens ) {
807
+ if ( bindValueCount == 1 && isEnclosedInParens && expandedParamPosition == originalParamPosition ) {
792
808
// short-circuit for performance when only 1 value and the
793
809
// placeholder is already enclosed in parentheses...
810
+ expandedParamPosition ++;
794
811
continue ;
795
812
}
796
813
797
814
if ( sb == null ) {
798
- sb = new StringBuilder ( sqlString .length () + 20 );
799
- sb .append ( sqlString );
815
+ sb = new StringBuilder ( sqlString );
816
+ }
817
+
818
+ if ( occurrenceExpansionSB == null ) {
819
+ occurrenceExpansionSB = new StringBuilder ();
820
+ }
821
+ else {
822
+ occurrenceExpansionSB .setLength ( 0 );
823
+ }
824
+
825
+ if ( !isEnclosedInParens ) {
826
+ occurrenceExpansionSB .append ( '(' );
800
827
}
801
828
802
- final String expansionListAsString ;
803
829
// HHH-8901
804
830
if ( bindValueMaxCount == 0 ) {
805
- if ( isEnclosedInParens ) {
806
- expansionListAsString = "null" ;
807
- }
808
- else {
809
- expansionListAsString = "(null)" ;
810
- }
831
+ occurrenceExpansionSB .append ( "null" );
811
832
}
812
833
else {
813
- // Shift 1 bit instead of multiplication by 2
814
- char [] chars ;
815
- if ( isEnclosedInParens ) {
816
- chars = new char [( bindValueMaxCount << 1 ) - 1 ];
817
- chars [0 ] = '?' ;
818
- for ( int i = 1 ; i < bindValueMaxCount ; i ++ ) {
819
- final int index = i << 1 ;
820
- chars [index - 1 ] = ',' ;
821
- chars [index ] = '?' ;
834
+ for ( int i = 0 ; i < bindValueMaxCount ; i ++ ) {
835
+ final String marker = parameterMarkerStrategy .createMarker (
836
+ expandedParamPosition + i ,
837
+ null
838
+ );
839
+ occurrenceExpansionSB .append ( marker );
840
+ if ( i + 1 < bindValueMaxCount ) {
841
+ occurrenceExpansionSB .append ( ',' );
822
842
}
823
843
}
824
- else {
825
- chars = new char [( bindValueMaxCount << 1 ) + 1 ];
826
- chars [0 ] = '(' ;
827
- chars [1 ] = '?' ;
828
- for ( int i = 1 ; i < bindValueMaxCount ; i ++ ) {
829
- final int index = i << 1 ;
830
- chars [index ] = ',' ;
831
- chars [index + 1 ] = '?' ;
832
- }
833
- chars [chars .length - 1 ] = ')' ;
834
- }
835
-
836
- expansionListAsString = new String (chars );
837
844
}
845
+ if ( !isEnclosedInParens ) {
846
+ occurrenceExpansionSB .append ( ')' );
847
+ }
848
+
849
+ sourceOffset = getNewSourceOffsetAfterReplacement ( sb , sourceOffset , occurrence , occurrenceExpansionSB .toString () );
838
850
839
- final int start = sourcePosition + offset ;
840
- final int end = start + 1 ;
841
- sb .replace ( start , end , expansionListAsString );
842
- offset += expansionListAsString .length () - 1 ;
851
+ expandedParamPosition += bindValueMaxCount ;
843
852
}
844
853
return sb == null ? sqlString : sb .toString ();
845
854
}
846
855
856
+ private int getNewSourceOffsetAfterReplacement (StringBuilder sb , int sourceOffset , ParameterOccurrence occurrence , String replacement ) {
857
+ final int start = occurrence .getSourcePosition () + sourceOffset ;
858
+ final int end = start + occurrence .getLength ();
859
+ sb .replace ( start , end , replacement );
860
+ return sourceOffset + ( replacement .length () - occurrence .getLength () );
861
+ }
862
+
847
863
public static int determineBindValueMaxCount (boolean paddingEnabled , int inExprLimit , int bindValueCount ) {
848
864
int bindValueMaxCount = bindValueCount ;
849
865
0 commit comments