@@ -2,6 +2,7 @@ use std::fmt::{self, Display, Write};
22
33use crate :: {
44 error:: { Error , Result } ,
5+ query:: QI ,
56 row:: { self , Row } ,
67} ;
78
@@ -113,20 +114,35 @@ impl SqlBuilder {
113114 }
114115 }
115116
116- pub ( crate ) fn finish ( mut self ) -> Result < String > {
117+ pub ( crate ) fn finish ( mut self , interp_flags : u8 ) -> Result < String > {
117118 let mut sql = String :: new ( ) ;
118119
119120 if let Self :: InProgress ( parts, _) = & self {
120121 for part in parts {
121122 match part {
122123 Part :: Text ( text) => sql. push_str ( text) ,
123124 Part :: Arg => {
124- self . error ( "unbound query argument" ) ;
125- break ;
125+ if QI :: has_bind ( interp_flags) {
126+ self . error ( "unbound query argument" ) ;
127+ break ;
128+ } else {
129+ // Push NULL as placeholder to prevent ClickHouse server error
130+ eprintln ! (
131+ "warning use QI::BIND template flag,bind() skipped for query: {}" ,
132+ self
133+ ) ;
134+ sql. push_str ( "NULL" ) ;
135+ }
126136 }
127137 Part :: Fields => {
128- self . error ( "unbound query argument ?fields" ) ;
129- break ;
138+ if QI :: has_fields ( interp_flags) {
139+ self . error ( "unbound query argument ?fields" ) ;
140+ break ;
141+ } else {
142+ // Skip ?fields binding entirely when FIELDS flag is not set
143+ eprintln ! ( "warning: use QI::FIELDS template flag, ?fields skipped for query: {}" , self ) ;
144+ // Don't push anything - just skip this part
145+ }
130146 }
131147 }
132148 }
@@ -194,18 +210,35 @@ mod tests {
194210 ) ;
195211
196212 assert_eq ! (
197- sql. finish( ) . unwrap( ) ,
213+ sql. finish( QI :: BIND ) . unwrap( ) ,
198214 r"SELECT `a`,`b` FROM test WHERE a = 'foo' AND b < 42"
199215 ) ;
200216 }
201217
218+ #[ test]
219+ fn skipped_fields ( ) {
220+ // Test that ?fields is skipped when FIELDS flag is not set
221+ let mut sql = SqlBuilder :: new ( "SELECT ?fields FROM test WHERE id = ?" ) ;
222+ sql. bind_arg ( 42 ) ;
223+
224+ // Without QI::FIELDS flag, ?fields should be skipped entirely
225+ // The bound ? becomes 42 as expected
226+ let result = sql. finish ( QI :: NONE ) . unwrap ( ) ;
227+ assert_eq ! ( result, "SELECT FROM test WHERE id = 42" ) ;
228+
229+ // Test case with unbound ? - should become NULL when BIND flag not set
230+ let sql2 = SqlBuilder :: new ( "SELECT ?fields FROM test WHERE id = ?" ) ;
231+ let result2 = sql2. finish ( QI :: NONE ) . unwrap ( ) ;
232+ assert_eq ! ( result2, "SELECT FROM test WHERE id = NULL" ) ;
233+ }
234+
202235 #[ test]
203236 fn in_clause ( ) {
204237 fn t ( arg : & [ & str ] , expected : & str ) {
205238 let mut sql = SqlBuilder :: new ( "SELECT ?fields FROM test WHERE a IN ?" ) ;
206239 sql. bind_arg ( arg) ;
207240 sql. bind_fields :: < Row > ( ) ;
208- assert_eq ! ( sql. finish( ) . unwrap( ) , expected) ;
241+ assert_eq ! ( sql. finish( QI :: BIND ) . unwrap( ) , expected) ;
209242 }
210243
211244 const ARGS : & [ & str ] = & [ "bar" , "baz" , "foobar" ] ;
@@ -228,7 +261,7 @@ mod tests {
228261 sql. bind_arg ( & [ "a?b" , "c?" ] [ ..] ) ;
229262 sql. bind_arg ( "a?" ) ;
230263 assert_eq ! (
231- sql. finish( ) . unwrap( ) ,
264+ sql. finish( QI :: BIND ) . unwrap( ) ,
232265 r"SELECT 1 FROM test WHERE a IN ['a?b','c?'] AND b = 'a?'"
233266 ) ;
234267 }
@@ -237,7 +270,7 @@ mod tests {
237270 fn question_escape ( ) {
238271 let sql = SqlBuilder :: new ( "SELECT 1 FROM test WHERE a IN 'a??b'" ) ;
239272 assert_eq ! (
240- sql. finish( ) . unwrap( ) ,
273+ sql. finish( QI :: BIND ) . unwrap( ) ,
241274 r"SELECT 1 FROM test WHERE a IN 'a?b'"
242275 ) ;
243276 }
@@ -246,38 +279,44 @@ mod tests {
246279 fn option_as_null ( ) {
247280 let mut sql = SqlBuilder :: new ( "SELECT 1 FROM test WHERE a = ?" ) ;
248281 sql. bind_arg ( None :: < u32 > ) ;
249- assert_eq ! ( sql. finish( ) . unwrap( ) , r"SELECT 1 FROM test WHERE a = NULL" ) ;
282+ assert_eq ! (
283+ sql. finish( QI :: BIND ) . unwrap( ) ,
284+ r"SELECT 1 FROM test WHERE a = NULL"
285+ ) ;
250286 }
251287
252288 #[ test]
253289 fn option_as_value ( ) {
254290 let mut sql = SqlBuilder :: new ( "SELECT 1 FROM test WHERE a = ?" ) ;
255291 sql. bind_arg ( Some ( 1u32 ) ) ;
256- assert_eq ! ( sql. finish( ) . unwrap( ) , r"SELECT 1 FROM test WHERE a = 1" ) ;
292+ assert_eq ! (
293+ sql. finish( QI :: BIND ) . unwrap( ) ,
294+ r"SELECT 1 FROM test WHERE a = 1"
295+ ) ;
257296 }
258297
259298 #[ test]
260299 fn failures ( ) {
261300 let mut sql = SqlBuilder :: new ( "SELECT 1" ) ;
262301 sql. bind_arg ( 42 ) ;
263- let err = sql. finish ( ) . unwrap_err ( ) ;
302+ let err = sql. finish ( QI :: BIND ) . unwrap_err ( ) ;
264303 assert ! ( err. to_string( ) . contains( "all arguments are already bound" ) ) ;
265304
266305 let mut sql = SqlBuilder :: new ( "SELECT ?fields" ) ;
267306 sql. bind_fields :: < Unnamed > ( ) ;
268- let err = sql. finish ( ) . unwrap_err ( ) ;
307+ let err = sql. finish ( QI :: BIND | QI :: FIELDS ) . unwrap_err ( ) ;
269308 assert ! ( err
270309 . to_string( )
271310 . contains( "argument ?fields cannot be used with non-struct row types" ) ) ;
272311
273312 let mut sql = SqlBuilder :: new ( "SELECT a FROM test WHERE b = ? AND c = ?" ) ;
274313 sql. bind_arg ( 42 ) ;
275- let err = sql. finish ( ) . unwrap_err ( ) ;
314+ let err = sql. finish ( QI :: BIND ) . unwrap_err ( ) ;
276315 assert ! ( err. to_string( ) . contains( "unbound query argument" ) ) ;
277316
278317 let mut sql = SqlBuilder :: new ( "SELECT ?fields FROM test WHERE b = ?" ) ;
279318 sql. bind_arg ( 42 ) ;
280- let err = sql. finish ( ) . unwrap_err ( ) ;
319+ let err = sql. finish ( QI :: BIND | QI :: FIELDS ) . unwrap_err ( ) ;
281320 assert ! ( err. to_string( ) . contains( "unbound query argument ?fields" ) ) ;
282321 }
283322}
0 commit comments