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