1
+ use std:: collections:: HashMap ;
1
2
use std:: num:: NonZeroUsize ;
2
3
use std:: sync:: { Arc , Mutex } ;
3
4
@@ -97,7 +98,8 @@ impl PgQueryStore {
97
98
///
98
99
/// Useful for preparing SQL queries for parsing or execution where named paramters are not supported.
99
100
pub fn convert_to_positional_params ( text : & str ) -> String {
100
- let mut result = String :: new ( ) ;
101
+ let mut result = String :: with_capacity ( text. len ( ) ) ;
102
+ let mut param_mapping: HashMap < & str , usize > = HashMap :: new ( ) ;
101
103
let mut param_index = 1 ;
102
104
let mut position = 0 ;
103
105
@@ -106,7 +108,17 @@ pub fn convert_to_positional_params(text: &str) -> String {
106
108
let token_text = & text[ position..position + token_len] ;
107
109
108
110
if matches ! ( token. kind, pgt_tokenizer:: TokenKind :: NamedParam { .. } ) {
109
- let replacement = format ! ( "${}" , param_index) ;
111
+ let idx = match param_mapping. get ( token_text) {
112
+ Some ( & index) => index,
113
+ None => {
114
+ let index = param_index;
115
+ param_mapping. insert ( token_text, index) ;
116
+ param_index += 1 ;
117
+ index
118
+ }
119
+ } ;
120
+
121
+ let replacement = format ! ( "${}" , idx) ;
110
122
let original_len = token_text. len ( ) ;
111
123
let replacement_len = replacement. len ( ) ;
112
124
@@ -116,8 +128,6 @@ pub fn convert_to_positional_params(text: &str) -> String {
116
128
if replacement_len < original_len {
117
129
result. push_str ( & " " . repeat ( original_len - replacement_len) ) ;
118
130
}
119
-
120
- param_index += 1 ;
121
131
} else {
122
132
result. push_str ( token_text) ;
123
133
}
@@ -142,6 +152,16 @@ mod tests {
142
152
) ;
143
153
}
144
154
155
+ #[ test]
156
+ fn test_convert_to_positional_params_with_duplicates ( ) {
157
+ let input = "select * from users where first_name = @one and starts_with(email, @one) and created_at > @two;" ;
158
+ let result = convert_to_positional_params ( input) ;
159
+ assert_eq ! (
160
+ result,
161
+ "select * from users where first_name = $1 and starts_with(email, $1 ) and created_at > $2 ;"
162
+ ) ;
163
+ }
164
+
145
165
#[ test]
146
166
fn test_plpgsql_syntax_error ( ) {
147
167
let input = "
0 commit comments