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