11use  super :: decode_column_name; 
22use  crate :: error:: Error ; 
33use  crate :: odbc:: { 
4-     connection:: MaybePrepared ,  ColumnData ,  OdbcArgumentValue ,  OdbcArguments ,  OdbcBatch ,   OdbcColumn , 
5-     OdbcQueryResult ,  OdbcRow ,  OdbcTypeInfo , 
4+     connection:: MaybePrepared ,  ColumnData ,  OdbcArgumentValue ,  OdbcArguments ,  OdbcBatch , 
5+     OdbcBufferSettings ,   OdbcColumn ,   OdbcQueryResult ,  OdbcRow ,  OdbcTypeInfo , 
66} ; 
77use  either:: Either ; 
88use  flume:: { SendError ,  Sender } ; 
99use  odbc_api:: buffers:: { AnySlice ,  BufferDesc ,  ColumnarAnyBuffer } ; 
1010use  odbc_api:: handles:: { AsStatementRef ,  Nullability ,  Statement } ; 
1111use  odbc_api:: DataType ; 
1212use  odbc_api:: { Cursor ,  IntoParameter ,  ResultSetMetadata } ; 
13- use  std:: cmp:: min; 
1413use  std:: sync:: Arc ; 
1514
1615// Bulk fetch implementation using columnar buffers instead of row-by-row fetching 
1716// This provides significant performance improvements by fetching rows in batches 
1817// and avoiding the slow `next_row()` method from odbc-api 
19- const  BATCH_SIZE :  usize  = 128 ; 
20- const  DEFAULT_TEXT_LEN :  usize  = 512 ; 
21- const  DEFAULT_BINARY_LEN :  usize  = 1024 ; 
22- const  DEFAULT_NUMERIC_TEXT_LEN :  usize  = 128 ; 
23- const  MIN_TEXT_LEN :  usize  = 1024 ; 
24- const  MAX_TEXT_LEN :  usize  = 4096 ; 
2518
2619struct  ColumnBinding  { 
2720    column :  OdbcColumn , 
2821    buffer_desc :  BufferDesc , 
2922} 
3023
31- fn  build_bindings < C > ( cursor :  & mut  C )  -> Result < Vec < ColumnBinding > ,  Error > 
24+ fn  build_bindings < C > ( 
25+     cursor :  & mut  C , 
26+     buffer_settings :  & OdbcBufferSettings , 
27+ )  -> Result < Vec < ColumnBinding > ,  Error > 
3228where 
3329    C :  ResultSetMetadata , 
3430{ 
4036            . col_nullability ( index as  u16 ) 
4137            . unwrap_or ( Nullability :: Unknown ) 
4238            . could_be_nullable ( ) ; 
43-         let  buffer_desc = map_buffer_desc ( cursor,  index as  u16 ,  & column. type_info ,  nullable) ?; 
39+         let  buffer_desc = map_buffer_desc ( 
40+             cursor, 
41+             index as  u16 , 
42+             & column. type_info , 
43+             nullable, 
44+             buffer_settings, 
45+         ) ?; 
4446        bindings. push ( ColumnBinding  { 
4547            column, 
4648            buffer_desc, 
@@ -67,21 +69,22 @@ pub fn execute_sql(
6769    maybe_prepared :  MaybePrepared , 
6870    args :  Option < OdbcArguments > , 
6971    tx :  & ExecuteSender , 
72+     buffer_settings :  OdbcBufferSettings , 
7073)  -> Result < ( ) ,  Error >  { 
7174    let  params = prepare_parameters ( args) ; 
7275
7376    let  affected = match  maybe_prepared { 
7477        MaybePrepared :: Prepared ( prepared)  => { 
7578            let  mut  prepared = prepared. lock ( ) . expect ( "prepared statement lock" ) ; 
7679            if  let  Some ( cursor)  = prepared. execute ( & params[ ..] ) ? { 
77-                 handle_cursor ( cursor,  tx) ; 
80+                 handle_cursor ( cursor,  tx,  buffer_settings ) ; 
7881            } 
7982            extract_rows_affected ( & mut  * prepared) 
8083        } 
8184        MaybePrepared :: NotPrepared ( sql)  => { 
8285            let  mut  preallocated = conn. preallocate ( ) . map_err ( Error :: from) ?; 
8386            if  let  Some ( cursor)  = preallocated. execute ( & sql,  & params[ ..] ) ? { 
84-                 handle_cursor ( cursor,  tx) ; 
87+                 handle_cursor ( cursor,  tx,  buffer_settings ) ; 
8588            } 
8689            extract_rows_affected ( & mut  preallocated) 
8790        } 
@@ -127,19 +130,19 @@ fn to_param(arg: OdbcArgumentValue) -> Box<dyn odbc_api::parameter::InputParamet
127130    } 
128131} 
129132
130- fn  handle_cursor < C > ( mut  cursor :  C ,  tx :  & ExecuteSender ) 
133+ fn  handle_cursor < C > ( mut  cursor :  C ,  tx :  & ExecuteSender ,   buffer_settings :   OdbcBufferSettings ) 
131134where 
132135    C :  Cursor  + ResultSetMetadata , 
133136{ 
134-     let  bindings = match  build_bindings ( & mut  cursor)  { 
137+     let  bindings = match  build_bindings ( & mut  cursor,   & buffer_settings )  { 
135138        Ok ( b)  => b, 
136139        Err ( e)  => { 
137140            send_error ( tx,  e) ; 
138141            return ; 
139142        } 
140143    } ; 
141144
142-     match  stream_rows ( cursor,  bindings,  tx)  { 
145+     match  stream_rows ( cursor,  bindings,  tx,  buffer_settings )  { 
143146        Ok ( true )  => { 
144147            let  _ = send_done ( tx,  0 ) ; 
145148        } 
@@ -181,6 +184,7 @@ fn map_buffer_desc<C>(
181184    _column_index :  u16 , 
182185    type_info :  & OdbcTypeInfo , 
183186    nullable :  bool , 
187+     buffer_settings :  & OdbcBufferSettings , 
184188)  -> Result < BufferDesc ,  Error > 
185189where 
186190    C :  ResultSetMetadata , 
@@ -200,9 +204,14 @@ where
200204        | DataType :: Varbinary  {  length } 
201205        | DataType :: LongVarbinary  {  length }  => BufferDesc :: Binary  { 
202206            length :  if  let  Some ( length)  = length { 
203-                 length. get ( ) . clamp ( MIN_TEXT_LEN ,  MAX_TEXT_LEN ) 
207+                 if  length. get ( )  < 255  { 
208+                     // Some drivers report 255 for max length 
209+                     length. get ( ) 
210+                 }  else  { 
211+                     buffer_settings. max_column_size 
212+                 } 
204213            }  else  { 
205-                 MAX_TEXT_LEN 
214+                 buffer_settings . max_column_size 
206215            } , 
207216        } , 
208217        DataType :: Char  {  length } 
@@ -216,16 +225,20 @@ where
216225            ..
217226        }  => BufferDesc :: Text  { 
218227            max_str_len :  if  let  Some ( length)  = length { 
219-                 length. get ( ) . clamp ( MIN_TEXT_LEN ,  MAX_TEXT_LEN ) 
228+                 if  length. get ( )  < 255  { 
229+                     length. get ( ) 
230+                 }  else  { 
231+                     buffer_settings. max_column_size 
232+                 } 
220233            }  else  { 
221-                 MAX_TEXT_LEN 
234+                 buffer_settings . max_column_size 
222235            } , 
223236        } , 
224237        DataType :: Unknown  => BufferDesc :: Text  { 
225-             max_str_len :  MAX_TEXT_LEN , 
238+             max_str_len :  buffer_settings . max_column_size , 
226239        } , 
227240        DataType :: Decimal  {  .. }  | DataType :: Numeric  {  .. }  => BufferDesc :: Text  { 
228-             max_str_len :  min ( DEFAULT_NUMERIC_TEXT_LEN ,   MAX_TEXT_LEN ) , 
241+             max_str_len :  buffer_settings . max_column_size , 
229242        } , 
230243    } ; 
231244
@@ -236,12 +249,13 @@ fn stream_rows<C>(
236249    cursor :  C , 
237250    bindings :  Vec < ColumnBinding > , 
238251    tx :  & ExecuteSender , 
252+     buffer_settings :  OdbcBufferSettings , 
239253)  -> Result < bool ,  Error > 
240254where 
241255    C :  Cursor  + ResultSetMetadata , 
242256{ 
243257    let  buffer_descriptions:  Vec < _ >  = bindings. iter ( ) . map ( |b| b. buffer_desc ) . collect ( ) ; 
244-     let  buffer = ColumnarAnyBuffer :: from_descs ( BATCH_SIZE ,  buffer_descriptions) ; 
258+     let  buffer = ColumnarAnyBuffer :: from_descs ( buffer_settings . batch_size ,  buffer_descriptions) ; 
245259    let  mut  row_set_cursor = cursor. bind_buffer ( buffer) ?; 
246260
247261    let  mut  receiver_open = true ; 
0 commit comments