@@ -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,39 @@ 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+ // Error on unbound arguments when BIND flag is set
127+ self . error ( "unbound query argument" ) ;
128+ break ;
129+ } else {
130+ // Push NULL as placeholder when BIND flag is not set
131+ eprintln ! (
132+ "warning: bind() called but QI::BIND flag not set, using NULL for query: {}" ,
133+ self
134+ ) ;
135+ sql. push_str ( "NULL" ) ;
136+ }
126137 }
127138 Part :: Fields => {
128- self . error ( "unbound query argument ?fields" ) ;
129- break ;
139+ if QI :: has_fields ( interp_flags) {
140+ self . error ( "unbound query argument ?fields" ) ;
141+ break ;
142+ } else {
143+ // Skip ?fields binding entirely when FIELDS flag is not set
144+ eprintln ! (
145+ "warning: use QI::FIELDS template flag, ?fields skipped for query: {}" ,
146+ self
147+ ) ;
148+ // Don't push anything - just skip this part
149+ }
130150 }
131151 }
132152 }
@@ -194,18 +214,35 @@ mod tests {
194214 ) ;
195215
196216 assert_eq ! (
197- sql. finish( ) . unwrap( ) ,
217+ sql. finish( QI :: BIND ) . unwrap( ) ,
198218 r"SELECT `a`,`b` FROM test WHERE a = 'foo' AND b < 42"
199219 ) ;
200220 }
201221
222+ #[ test]
223+ fn skipped_fields ( ) {
224+ // Test that ?fields is skipped when FIELDS flag is not set
225+ let mut sql = SqlBuilder :: new ( "SELECT ?fields FROM test WHERE id = ?" ) ;
226+ sql. bind_arg ( 42 ) ;
227+
228+ // Without QI::FIELDS flag, ?fields should be skipped entirely
229+ // The bound ? becomes 42 as expected
230+ let result = sql. finish ( QI :: NONE ) . unwrap ( ) ;
231+ assert_eq ! ( result, "SELECT FROM test WHERE id = 42" ) ;
232+
233+ // Test case with unbound ? - should become NULL when BIND flag not set
234+ let sql2 = SqlBuilder :: new ( "SELECT ?fields FROM test WHERE id = ?" ) ;
235+ let result2 = sql2. finish ( QI :: NONE ) . unwrap ( ) ;
236+ assert_eq ! ( result2, "SELECT FROM test WHERE id = NULL" ) ;
237+ }
238+
202239 #[ test]
203240 fn in_clause ( ) {
204241 fn t ( arg : & [ & str ] , expected : & str ) {
205242 let mut sql = SqlBuilder :: new ( "SELECT ?fields FROM test WHERE a IN ?" ) ;
206243 sql. bind_arg ( arg) ;
207244 sql. bind_fields :: < Row > ( ) ;
208- assert_eq ! ( sql. finish( ) . unwrap( ) , expected) ;
245+ assert_eq ! ( sql. finish( QI :: BIND ) . unwrap( ) , expected) ;
209246 }
210247
211248 const ARGS : & [ & str ] = & [ "bar" , "baz" , "foobar" ] ;
@@ -228,7 +265,7 @@ mod tests {
228265 sql. bind_arg ( & [ "a?b" , "c?" ] [ ..] ) ;
229266 sql. bind_arg ( "a?" ) ;
230267 assert_eq ! (
231- sql. finish( ) . unwrap( ) ,
268+ sql. finish( QI :: BIND ) . unwrap( ) ,
232269 r"SELECT 1 FROM test WHERE a IN ['a?b','c?'] AND b = 'a?'"
233270 ) ;
234271 }
@@ -237,7 +274,7 @@ mod tests {
237274 fn question_escape ( ) {
238275 let sql = SqlBuilder :: new ( "SELECT 1 FROM test WHERE a IN 'a??b'" ) ;
239276 assert_eq ! (
240- sql. finish( ) . unwrap( ) ,
277+ sql. finish( QI :: BIND ) . unwrap( ) ,
241278 r"SELECT 1 FROM test WHERE a IN 'a?b'"
242279 ) ;
243280 }
@@ -246,39 +283,51 @@ mod tests {
246283 fn option_as_null ( ) {
247284 let mut sql = SqlBuilder :: new ( "SELECT 1 FROM test WHERE a = ?" ) ;
248285 sql. bind_arg ( None :: < u32 > ) ;
249- assert_eq ! ( sql. finish( ) . unwrap( ) , r"SELECT 1 FROM test WHERE a = NULL" ) ;
286+ assert_eq ! (
287+ sql. finish( QI :: BIND ) . unwrap( ) ,
288+ r"SELECT 1 FROM test WHERE a = NULL"
289+ ) ;
250290 }
251291
252292 #[ test]
253293 fn option_as_value ( ) {
254294 let mut sql = SqlBuilder :: new ( "SELECT 1 FROM test WHERE a = ?" ) ;
255295 sql. bind_arg ( Some ( 1u32 ) ) ;
256- assert_eq ! ( sql. finish( ) . unwrap( ) , r"SELECT 1 FROM test WHERE a = 1" ) ;
296+ assert_eq ! (
297+ sql. finish( QI :: BIND ) . unwrap( ) ,
298+ r"SELECT 1 FROM test WHERE a = 1"
299+ ) ;
257300 }
258301
259302 #[ test]
260303 fn failures ( ) {
261304 let mut sql = SqlBuilder :: new ( "SELECT 1" ) ;
262305 sql. bind_arg ( 42 ) ;
263- let err = sql. finish ( ) . unwrap_err ( ) ;
306+ let err = sql. finish ( QI :: BIND ) . unwrap_err ( ) ;
264307 assert ! ( err. to_string( ) . contains( "all arguments are already bound" ) ) ;
265308
266309 let mut sql = SqlBuilder :: new ( "SELECT ?fields" ) ;
267310 sql. bind_fields :: < Unnamed > ( ) ;
268- let err = sql. finish ( ) . unwrap_err ( ) ;
311+ let err = sql. finish ( QI :: BIND | QI :: FIELDS ) . unwrap_err ( ) ;
269312 assert ! (
270313 err. to_string( )
271314 . contains( "argument ?fields cannot be used with non-struct row types" )
272315 ) ;
273316
317+ //new changes ->
318+ // let err = sql.finish().unwrap_err();
319+ // assert!(
320+ // err.to_string()
321+ // .contains("argument ?fields cannot be used with non-struct row types")
322+ // );
274323 let mut sql = SqlBuilder :: new ( "SELECT a FROM test WHERE b = ? AND c = ?" ) ;
275324 sql. bind_arg ( 42 ) ;
276- let err = sql. finish ( ) . unwrap_err ( ) ;
325+ let err = sql. finish ( QI :: BIND ) . unwrap_err ( ) ;
277326 assert ! ( err. to_string( ) . contains( "unbound query argument" ) ) ;
278327
279328 let mut sql = SqlBuilder :: new ( "SELECT ?fields FROM test WHERE b = ?" ) ;
280329 sql. bind_arg ( 42 ) ;
281- let err = sql. finish ( ) . unwrap_err ( ) ;
330+ let err = sql. finish ( QI :: BIND | QI :: FIELDS ) . unwrap_err ( ) ;
282331 assert ! ( err. to_string( ) . contains( "unbound query argument ?fields" ) ) ;
283332 }
284333}
0 commit comments