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