@@ -3,6 +3,7 @@ use crate::encode::Encode;
33use crate :: error:: BoxDynError ;
44use crate :: odbc:: { DataTypeExt , Odbc , OdbcArgumentValue , OdbcTypeInfo , OdbcValueRef } ;
55use crate :: types:: Type ;
6+ use crate :: type_info:: TypeInfo ;
67use chrono:: { DateTime , FixedOffset , Local , NaiveDate , NaiveDateTime , NaiveTime , Utc } ;
78use odbc_api:: DataType ;
89
@@ -192,11 +193,13 @@ fn parse_yyyymmdd_text_as_naive_date(s: &str) -> Option<NaiveDate> {
192193
193194fn get_text_from_value ( value : & OdbcValueRef < ' _ > ) -> Result < Option < String > , BoxDynError > {
194195 if let Some ( text) = value. text {
195- return Ok ( Some ( text. trim ( ) . to_string ( ) ) ) ;
196+ let trimmed = text. trim_matches ( '\u{0}' ) . trim ( ) ;
197+ return Ok ( Some ( trimmed. to_string ( ) ) ) ;
196198 }
197199 if let Some ( bytes) = value. blob {
198200 let s = std:: str:: from_utf8 ( bytes) ?;
199- return Ok ( Some ( s. trim ( ) . to_string ( ) ) ) ;
201+ let trimmed = s. trim_matches ( '\u{0}' ) . trim ( ) ;
202+ return Ok ( Some ( trimmed. to_string ( ) ) ) ;
200203 }
201204 Ok ( None )
202205}
@@ -208,31 +211,51 @@ impl<'r> Decode<'r, Odbc> for NaiveDate {
208211 if let Some ( date) = parse_yyyymmdd_text_as_naive_date ( & text) {
209212 return Ok ( date) ;
210213 }
211- return Ok ( text. parse ( ) ?) ;
214+ if let Ok ( date) = text. parse ( ) {
215+ return Ok ( date) ;
216+ }
212217 }
213218
214219 // Handle numeric YYYYMMDD format (for databases that return as numbers)
215220 if let Some ( int_val) = value. int {
216221 if let Some ( date) = parse_yyyymmdd_as_naive_date ( int_val) {
217222 return Ok ( date) ;
218223 }
224+ return Err ( format ! (
225+ "ODBC: cannot decode NaiveDate from integer '{}': not in YYYYMMDD range" ,
226+ int_val
227+ )
228+ . into ( ) ) ;
219229 }
220230
221231 // Handle float values similarly
222232 if let Some ( float_val) = value. float {
223233 if let Some ( date) = parse_yyyymmdd_as_naive_date ( float_val as i64 ) {
224234 return Ok ( date) ;
225235 }
236+ return Err ( format ! (
237+ "ODBC: cannot decode NaiveDate from float '{}': not in YYYYMMDD range" ,
238+ float_val
239+ )
240+ . into ( ) ) ;
226241 }
227242
228- Err ( "ODBC: cannot decode NaiveDate" . into ( ) )
243+ Err ( format ! (
244+ "ODBC: cannot decode NaiveDate from value with type '{}'" ,
245+ value. type_info. name( )
246+ )
247+ . into ( ) )
229248 }
230249}
231250
232251impl < ' r > Decode < ' r , Odbc > for NaiveTime {
233252 fn decode ( value : OdbcValueRef < ' r > ) -> Result < Self , BoxDynError > {
234- let s = <String as Decode < ' r , Odbc > >:: decode ( value) ?;
235- Ok ( s. parse ( ) ?)
253+ let mut s = <String as Decode < ' r , Odbc > >:: decode ( value) ?;
254+ if s. ends_with ( '\u{0}' ) {
255+ s = s. trim_end_matches ( '\u{0}' ) . to_string ( ) ;
256+ }
257+ let s_trimmed = s. trim ( ) ;
258+ Ok ( s_trimmed. parse ( ) . map_err ( |e| format ! ( "ODBC: cannot decode NaiveTime from '{}': {}" , s_trimmed, e) ) ?)
236259 }
237260}
238261
@@ -249,13 +272,18 @@ impl<'r> Decode<'r, Odbc> for NaiveDateTime {
249272 if let Ok ( dt) = NaiveDateTime :: parse_from_str ( s_trimmed, "%Y-%m-%d %H:%M:%S" ) {
250273 return Ok ( dt) ;
251274 }
252- Ok ( s_trimmed. parse ( ) ?)
275+ Ok ( s_trimmed
276+ . parse ( )
277+ . map_err ( |e| format ! ( "ODBC: cannot decode NaiveDateTime from '{}': {}" , s_trimmed, e) ) ?)
253278 }
254279}
255280
256281impl < ' r > Decode < ' r , Odbc > for DateTime < Utc > {
257282 fn decode ( value : OdbcValueRef < ' r > ) -> Result < Self , BoxDynError > {
258- let s = <String as Decode < ' r , Odbc > >:: decode ( value) ?;
283+ let mut s = <String as Decode < ' r , Odbc > >:: decode ( value) ?;
284+ if s. ends_with ( '\u{0}' ) {
285+ s = s. trim_end_matches ( '\u{0}' ) . to_string ( ) ;
286+ }
259287 let s_trimmed = s. trim ( ) ;
260288
261289 // First try to parse as a UTC timestamp with timezone
@@ -273,13 +301,16 @@ impl<'r> Decode<'r, Odbc> for DateTime<Utc> {
273301 return Ok ( DateTime :: < Utc > :: from_naive_utc_and_offset ( naive_dt, Utc ) ) ;
274302 }
275303
276- Err ( format ! ( "Cannot parse '{}' as DateTime<Utc>" , s_trimmed) . into ( ) )
304+ Err ( format ! ( "ODBC: cannot decode DateTime<Utc> from '{}' " , s_trimmed) . into ( ) )
277305 }
278306}
279307
280308impl < ' r > Decode < ' r , Odbc > for DateTime < FixedOffset > {
281309 fn decode ( value : OdbcValueRef < ' r > ) -> Result < Self , BoxDynError > {
282- let s = <String as Decode < ' r , Odbc > >:: decode ( value) ?;
310+ let mut s = <String as Decode < ' r , Odbc > >:: decode ( value) ?;
311+ if s. ends_with ( '\u{0}' ) {
312+ s = s. trim_end_matches ( '\u{0}' ) . to_string ( ) ;
313+ }
283314 let s_trimmed = s. trim ( ) ;
284315
285316 // First try to parse as a timestamp with timezone/offset
@@ -297,14 +328,21 @@ impl<'r> Decode<'r, Odbc> for DateTime<FixedOffset> {
297328 return Ok ( DateTime :: < Utc > :: from_naive_utc_and_offset ( naive_dt, Utc ) . fixed_offset ( ) ) ;
298329 }
299330
300- Err ( format ! ( "Cannot parse '{}' as DateTime<FixedOffset>" , s_trimmed) . into ( ) )
331+ Err ( format ! ( "ODBC: cannot decode DateTime<FixedOffset> from '{}' " , s_trimmed) . into ( ) )
301332 }
302333}
303334
304335impl < ' r > Decode < ' r , Odbc > for DateTime < Local > {
305336 fn decode ( value : OdbcValueRef < ' r > ) -> Result < Self , BoxDynError > {
306- let s = <String as Decode < ' r , Odbc > >:: decode ( value) ?;
307- Ok ( s. parse :: < DateTime < Utc > > ( ) ?. with_timezone ( & Local ) )
337+ let mut s = <String as Decode < ' r , Odbc > >:: decode ( value) ?;
338+ if s. ends_with ( '\u{0}' ) {
339+ s = s. trim_end_matches ( '\u{0}' ) . to_string ( ) ;
340+ }
341+ let s_trimmed = s. trim ( ) ;
342+ Ok ( s_trimmed
343+ . parse :: < DateTime < Utc > > ( )
344+ . map_err ( |e| format ! ( "ODBC: cannot decode DateTime<Local> from '{}' as DateTime<Utc>: {}" , s_trimmed, e) ) ?
345+ . with_timezone ( & Local ) )
308346 }
309347}
310348
0 commit comments