1use bytes::{BufMut, Bytes, BytesMut};
4use std::{
5 collections::VecDeque,
6 env,
7 io::{Read, Write},
8 net::{SocketAddr, TcpStream},
9};
10
11use crate::{
12 arc4::*,
13 blr,
14 consts::{AuthPluginType, ProtocolVersion, WireOp},
15 events::*,
16 srp::*,
17 util::*,
18 wire::*,
19 xsqlda::{parse_xsqlda, xsqlda_to_blr, PrepareInfo, XSqlVar, XSQLDA_DESCRIBE_VARS},
20};
21use rsfbclient_core::*;
22
23type RustDbHandle = DbHandle;
24type RustTrHandle = TrHandle;
25type RustStmtHandle = StmtHandle;
26
27fn fetch_batch_size() -> u32 {
30 env::var("FB_FETCH_BATCH")
31 .ok()
32 .and_then(|v| v.parse().ok())
33 .filter(|&n| n > 0)
34 .unwrap_or(200)
35}
36
37enum FetchOne {
41 Row(Vec<ParsedColumn>),
43 BatchEnd,
46 End,
48}
49
50pub struct RustFbClient {
52 conn: Option<FirebirdWireConnection>,
53 charset: Charset,
54}
55
56#[derive(Default, Clone)]
58pub struct RustFbClientAttachmentConfig {
59 pub host: String,
60 pub port: u16,
61 pub db_name: String,
62 pub user: String,
63 pub pass: String,
64 pub role_name: Option<String>,
65}
66
67pub struct FirebirdWireConnection {
69 socket: FbStream,
71
72 pub(crate) version: ProtocolVersion,
74
75 buff: Box<[u8]>,
77
78 pending: Bytes,
86
87 lazy_count: u32,
89
90 pub(crate) charset: Charset,
91
92 pub(crate) auth_plugin: Option<AuthPlugin>,
94 pub(crate) srp_key: [u8; 32],
96
97 event_channel: Option<EventChannel>,
101
102 next_event_id: u32,
104}
105
106pub struct StmtHandleData {
108 handle: RustStmtHandle,
110 xsqlda: Vec<XSqlVar>,
112 blr: Bytes,
114 param_count: usize,
116 prefetched: VecDeque<Vec<Column>>,
118 cursor_eof: bool,
120}
121
122impl RustFbClient {
123 pub fn new(charset: Charset) -> Self {
125 Self {
126 conn: None,
127 charset,
128 }
129 }
130}
131
132impl FirebirdClientDbOps for RustFbClient {
133 type DbHandle = RustDbHandle;
134 type AttachmentConfig = RustFbClientAttachmentConfig;
135
136 fn attach_database(
137 &mut self,
138 config: &Self::AttachmentConfig,
139 dialect: Dialect,
140 no_db_triggers: bool,
141 ) -> Result<RustDbHandle, FbError> {
142 let host = config.host.as_str();
143 let port = config.port;
144 let db_name = config.db_name.as_str();
145 let user = config.user.as_str();
146 let pass = config.pass.as_str();
147 let role = match &config.role_name {
148 Some(ro) => Some(ro.as_str()),
149 None => None,
150 };
151
152 let mut conn = match self.conn.take() {
154 Some(conn) => conn,
155 None => FirebirdWireConnection::connect(
156 host,
157 port,
158 db_name,
159 user,
160 pass,
161 self.charset.clone(),
162 )?,
163 };
164
165 let attach_result =
166 conn.attach_database(db_name, user, pass, role, dialect, no_db_triggers);
167
168 self.conn.replace(conn);
170
171 attach_result
172 }
173
174 fn detach_database(&mut self, db_handle: &mut RustDbHandle) -> Result<(), FbError> {
175 self.conn
176 .as_mut()
177 .map(|conn| conn.detach_database(db_handle))
178 .unwrap_or_else(err_client_not_connected)
179 }
180
181 fn drop_database(&mut self, db_handle: &mut RustDbHandle) -> Result<(), FbError> {
182 self.conn
183 .as_mut()
184 .map(|conn| conn.drop_database(db_handle))
185 .unwrap_or_else(err_client_not_connected)
186 }
187
188 fn create_database(
189 &mut self,
190 config: &Self::AttachmentConfig,
191 page_size: Option<u32>,
192 dialect: Dialect,
193 ) -> Result<RustDbHandle, FbError> {
194 let host = config.host.as_str();
195 let port = config.port;
196 let db_name = config.db_name.as_str();
197 let user = config.user.as_str();
198 let pass = config.pass.as_str();
199 let role = match &config.role_name {
200 Some(ro) => Some(ro.as_str()),
201 None => None,
202 };
203
204 let mut conn = match self.conn.take() {
206 Some(conn) => conn,
207 None => FirebirdWireConnection::connect(
208 host,
209 port,
210 db_name,
211 user,
212 pass,
213 self.charset.clone(),
214 )?,
215 };
216
217 let attach_result = conn.create_database(db_name, user, pass, page_size, role, dialect);
218
219 self.conn.replace(conn);
221
222 attach_result
223 }
224}
225
226impl FirebirdClientSqlOps for RustFbClient {
227 type DbHandle = RustDbHandle;
228 type TrHandle = RustTrHandle;
229 type StmtHandle = StmtHandleData;
230
231 fn begin_transaction(
232 &mut self,
233 db_handle: &mut Self::DbHandle,
234 confs: TransactionConfiguration,
235 ) -> Result<Self::TrHandle, FbError> {
236 self.conn
237 .as_mut()
238 .map(|conn| conn.begin_transaction(db_handle, confs))
239 .unwrap_or_else(err_client_not_connected)
240 }
241
242 fn transaction_operation(
243 &mut self,
244 tr_handle: &mut Self::TrHandle,
245 op: TrOp,
246 ) -> Result<(), FbError> {
247 self.conn
248 .as_mut()
249 .map(|conn| conn.transaction_operation(tr_handle, op))
250 .unwrap_or_else(err_client_not_connected)
251 }
252
253 fn exec_immediate(
254 &mut self,
255 _db_handle: &mut Self::DbHandle,
256 tr_handle: &mut Self::TrHandle,
257 dialect: Dialect,
258 sql: &str,
259 ) -> Result<(), FbError> {
260 self.conn
261 .as_mut()
262 .map(|conn| conn.exec_immediate(tr_handle, dialect, sql))
263 .unwrap_or_else(err_client_not_connected)
264 }
265
266 fn prepare_statement(
267 &mut self,
268 db_handle: &mut Self::DbHandle,
269 tr_handle: &mut Self::TrHandle,
270 dialect: Dialect,
271 sql: &str,
272 ) -> Result<(StmtType, Self::StmtHandle), FbError> {
273 self.conn
274 .as_mut()
275 .map(|conn| conn.prepare_statement(db_handle, tr_handle, dialect, sql))
276 .unwrap_or_else(err_client_not_connected)
277 }
278
279 fn free_statement(
280 &mut self,
281 stmt_handle: &mut Self::StmtHandle,
282 op: FreeStmtOp,
283 ) -> Result<(), FbError> {
284 self.conn
285 .as_mut()
286 .map(|conn| conn.free_statement(stmt_handle, op))
287 .unwrap_or_else(err_client_not_connected)
288 }
289
290 fn execute(
291 &mut self,
292 _db_handle: &mut Self::DbHandle,
293 tr_handle: &mut Self::TrHandle,
294 stmt_handle: &mut Self::StmtHandle,
295 params: Vec<SqlType>,
296 ) -> Result<usize, FbError> {
297 self.conn
298 .as_mut()
299 .map(|conn| conn.execute(tr_handle, stmt_handle, ¶ms))
300 .unwrap_or_else(err_client_not_connected)
301 }
302
303 fn execute2(
304 &mut self,
305 _db_handle: &mut Self::DbHandle,
306 tr_handle: &mut Self::TrHandle,
307 stmt_handle: &mut Self::StmtHandle,
308 params: Vec<SqlType>,
309 ) -> Result<Vec<Column>, FbError> {
310 self.conn
311 .as_mut()
312 .map(|conn| conn.execute2(tr_handle, stmt_handle, ¶ms))
313 .unwrap_or_else(err_client_not_connected)
314 }
315
316 fn fetch(
317 &mut self,
318 _db_handle: &mut Self::DbHandle,
319 tr_handle: &mut Self::TrHandle,
320 stmt_handle: &mut Self::StmtHandle,
321 ) -> Result<Option<Vec<Column>>, FbError> {
322 self.conn
323 .as_mut()
324 .map(|conn| conn.fetch(tr_handle, stmt_handle))
325 .unwrap_or_else(err_client_not_connected)
326 }
327}
328
329impl FirebirdClientDbEvents for RustFbClient {
330 fn wait_for_event(
331 &mut self,
332 db_handle: &mut Self::DbHandle,
333 name: String,
334 ) -> Result<(), FbError> {
335 self.conn
336 .as_mut()
337 .map(|conn| conn.wait_for_event(db_handle, &name))
338 .unwrap_or_else(err_client_not_connected)
339 }
340}
341
342fn err_client_not_connected<T>() -> Result<T, FbError> {
343 Err("Client not connected to the server, call `attach_database` to connect".into())
344}
345
346impl FirebirdWireConnection {
347 pub fn connect(
349 host: &str,
350 port: u16,
351 db_name: &str,
352 user: &str,
353 pass: &str,
354 charset: Charset,
355 ) -> Result<Self, FbError> {
356 let socket = TcpStream::connect((host, port))?;
357 let _ = socket.set_nodelay(true);
362
363 let username =
365 env::var("USER").unwrap_or_else(|_| env::var("USERNAME").unwrap_or_default());
366 let hostname = socket
367 .local_addr()
368 .map(|addr| addr.to_string())
369 .unwrap_or_default();
370
371 let mut socket = FbStream::Plain(socket);
372
373 let srp_key: [u8; 32] = rand::random();
375
376 let req = connect(db_name, user, &username, &hostname, &srp_key);
377 socket.write_all(&req)?;
378 socket.flush()?;
379
380 let mut buff = vec![0; BUFFER_LENGTH as usize * 2].into_boxed_slice();
382 let mut pending = Bytes::new();
383
384 let ConnectionResponse {
385 version,
386 mut auth_plugin,
387 continue_auth,
388 } = read_with(&mut socket, &mut buff, &mut pending, &mut 0, |resp, _| {
389 parse_accept(resp)
390 })?;
391
392 if let Some(auth_plugin) = &mut auth_plugin {
393 loop {
394 match auth_plugin.kind {
395 plugin @ AuthPluginType::Srp => {
396 let srp = SrpClient::<sha1::Sha1>::new(&srp_key, &SRP_GROUP);
397
398 if let Some(data) = auth_plugin.data.clone() {
399 if continue_auth {
400 socket = srp_auth(
402 socket,
403 &mut buff,
404 &mut pending,
405 srp,
406 plugin,
407 user,
408 pass,
409 &data,
410 )?;
411 }
412
413 break;
415 } else {
416 socket.write_all(&cont_auth(
420 hex::encode(srp.get_a_pub()).as_bytes(),
421 plugin,
422 AuthPluginType::plugin_list(),
423 &[],
424 ))?;
425 socket.flush()?;
426
427 *auth_plugin = read_with(
428 &mut socket,
429 &mut buff,
430 &mut pending,
431 &mut 0,
432 |resp, _| parse_cont_auth(resp),
433 )?;
434 }
435 }
436 plugin @ AuthPluginType::Srp256 => {
437 let srp = SrpClient::<sha2::Sha256>::new(&srp_key, &SRP_GROUP);
438
439 if let Some(data) = auth_plugin.data.clone() {
440 if continue_auth {
441 socket = srp_auth(
443 socket,
444 &mut buff,
445 &mut pending,
446 srp,
447 plugin,
448 user,
449 pass,
450 &data,
451 )?;
452 }
453
454 break;
456 } else {
457 socket.write_all(&cont_auth(
461 hex::encode(srp.get_a_pub()).as_bytes(),
462 plugin,
463 AuthPluginType::plugin_list(),
464 &[],
465 ))?;
466 socket.flush()?;
467
468 *auth_plugin = read_with(
469 &mut socket,
470 &mut buff,
471 &mut pending,
472 &mut 0,
473 |resp, _| parse_cont_auth(resp),
474 )?;
475 }
476 }
477 }
478 }
479 }
480
481 Ok(Self {
482 socket,
483 version,
484 buff,
485 pending,
486 lazy_count: 0,
487 charset,
488 auth_plugin: if continue_auth {
489 None
491 } else {
492 auth_plugin
494 },
495 srp_key,
496 event_channel: None,
497 next_event_id: 1,
498 })
499 }
500
501 pub fn create_database(
503 &mut self,
504 db_name: &str,
505 user: &str,
506 pass: &str,
507 page_size: Option<u32>,
508 role_name: Option<&str>,
509 dialect: Dialect,
510 ) -> Result<DbHandle, FbError> {
511 self.socket.write_all(&create(
512 db_name,
513 user,
514 pass,
515 self.version,
516 self.charset.clone(),
517 page_size,
518 role_name,
519 dialect,
520 self.auth_plugin.as_ref(),
521 &self.srp_key,
522 )?)?;
523 self.socket.flush()?;
524
525 let resp = self.read_response()?;
526
527 Ok(DbHandle(resp.handle))
528 }
529
530 pub fn attach_database(
532 &mut self,
533 db_name: &str,
534 user: &str,
535 pass: &str,
536 role_name: Option<&str>,
537 dialect: Dialect,
538 no_db_triggers: bool,
539 ) -> Result<DbHandle, FbError> {
540 self.socket.write_all(&attach(
541 db_name,
542 user,
543 pass,
544 self.version,
545 self.charset.clone(),
546 role_name,
547 dialect,
548 no_db_triggers,
549 self.auth_plugin.as_ref(),
550 &self.srp_key,
551 )?)?;
552 self.socket.flush()?;
553
554 let resp = self.read_response()?;
555
556 Ok(DbHandle(resp.handle))
557 }
558
559 pub fn detach_database(&mut self, db_handle: &mut DbHandle) -> Result<(), FbError> {
561 self.close_event_channel();
563
564 self.socket.write_all(&detach(db_handle.0))?;
565 self.socket.flush()?;
566
567 self.read_response()?;
568
569 Ok(())
570 }
571
572 pub fn drop_database(&mut self, db_handle: &mut DbHandle) -> Result<(), FbError> {
574 self.close_event_channel();
576
577 self.socket.write_all(&drop_database(db_handle.0))?;
578 self.socket.flush()?;
579
580 self.read_response()?;
581
582 Ok(())
583 }
584
585 pub fn wait_for_event(&mut self, db_handle: &mut DbHandle, name: &str) -> Result<(), FbError> {
591 let name = normalize_event_name(name)?;
592
593 self.open_event_channel(db_handle)?;
594
595 let event_id = self.new_event_id();
602 let counters = self.que_events(db_handle, name, 0, event_id)?;
603 let posted = event_count(&counters, name)?;
604
605 let event_id = self.new_event_id();
608 self.que_events(db_handle, name, posted, event_id)?;
609
610 Ok(())
611 }
612
613 fn new_event_id(&mut self) -> u32 {
619 let event_id = self.next_event_id;
620
621 self.next_event_id = self.next_event_id.wrapping_add(1).max(1);
622
623 event_id
624 }
625
626 fn que_events(
630 &mut self,
631 db_handle: &mut DbHandle,
632 name: &str,
633 count: u32,
634 event_id: u32,
635 ) -> Result<Vec<(String, u32)>, FbError> {
636 let epb = event_block(&self.charset, [(name, count)])?;
639
640 self.socket
641 .write_all(&que_events(db_handle.0, &epb, event_id))?;
642 self.socket.flush()?;
643
644 self.read_response()?;
647
648 let channel = match self.event_channel.as_mut() {
649 Some(channel) => channel,
650 None => return Err(FbError::from("The event channel was closed")),
651 };
652
653 match channel.recv_event(event_id) {
654 Ok(counters) => Ok(counters),
655
656 Err(err) => {
657 self.event_channel = None;
661 self.cancel_events(db_handle, event_id).ok();
662
663 Err(err)
664 }
665 }
666 }
667
668 fn cancel_events(&mut self, db_handle: &mut DbHandle, event_id: u32) -> Result<(), FbError> {
670 self.socket
671 .write_all(&cancel_events(db_handle.0, event_id))?;
672 self.socket.flush()?;
673
674 self.read_response()?;
675
676 Ok(())
677 }
678
679 fn open_event_channel(&mut self, db_handle: &mut DbHandle) -> Result<(), FbError> {
682 if matches!(&self.event_channel, Some(channel) if channel.db_handle() == db_handle.0) {
683 return Ok(());
684 }
685 self.event_channel = None;
686
687 self.socket.write_all(&connect_request(db_handle.0))?;
688 self.socket.flush()?;
689
690 let resp = self.read_response()?;
691 let port = parse_aux_port(&resp.data)?;
692
693 let peer = self.socket.peer_addr()?;
696 self.event_channel = Some(EventChannel::open(
697 db_handle.0,
698 self.charset.clone(),
699 peer,
700 port,
701 )?);
702
703 Ok(())
704 }
705
706 fn close_event_channel(&mut self) {
708 self.event_channel = None;
709 }
710
711 pub fn begin_transaction(
713 &mut self,
714 db_handle: &mut DbHandle,
715 confs: TransactionConfiguration,
716 ) -> Result<TrHandle, FbError> {
717 let mut tpb = vec![
718 ibase::isc_tpb_version3 as u8,
719 confs.isolation.into(),
720 confs.data_access as u8,
721 confs.lock_resolution.into(),
722 ];
723 if let TrLockResolution::Wait(Some(time)) = confs.lock_resolution {
724 tpb.push(ibase::isc_tpb_lock_timeout as u8);
725 tpb.push(4 as u8);
726 tpb.extend_from_slice(&time.to_le_bytes());
727 }
728
729 if let TrIsolationLevel::ReadCommited(rec) = confs.isolation {
730 tpb.push(rec as u8);
731 }
732
733 self.socket.write_all(&transaction(db_handle.0, &tpb))?;
734 self.socket.flush()?;
735
736 let resp = self.read_response()?;
737
738 Ok(TrHandle(resp.handle))
739 }
740
741 pub fn transaction_operation(
743 &mut self,
744 tr_handle: &mut TrHandle,
745 op: TrOp,
746 ) -> Result<(), FbError> {
747 self.socket
748 .write_all(&transaction_operation(tr_handle.0, op))?;
749 self.socket.flush()?;
750
751 self.read_response()?;
752
753 Ok(())
754 }
755
756 pub fn exec_immediate(
758 &mut self,
759 tr_handle: &mut TrHandle,
760 dialect: Dialect,
761 sql: &str,
762 ) -> Result<(), FbError> {
763 self.socket.write_all(&exec_immediate(
764 tr_handle.0,
765 dialect as u32,
766 sql,
767 &self.charset,
768 )?)?;
769 self.socket.flush()?;
770
771 self.read_response()?;
772
773 Ok(())
774 }
775
776 pub fn prepare_statement(
780 &mut self,
781 db_handle: &mut DbHandle,
782 tr_handle: &mut TrHandle,
783 dialect: Dialect,
784 sql: &str,
785 ) -> Result<(StmtType, StmtHandleData), FbError> {
786 self.socket.write_all(&allocate_statement(db_handle.0))?;
788 self.socket.write_all(&prepare_statement(
790 tr_handle.0,
791 u32::MAX,
792 dialect as u32,
793 sql,
794 &self.charset,
795 )?)?;
796 self.socket.flush()?;
797
798 let (stmt_handle, mut prepare_data) = read_with(
802 &mut self.socket,
803 &mut self.buff,
804 &mut self.pending,
805 &mut self.lazy_count,
806 |resp, lazy_count| {
807 let op_code = skip_lazy_responses(resp, lazy_count)?;
809 if op_code != WireOp::Response as u32 {
810 return err_conn_rejected(op_code);
811 }
812 let stmt_handle = StmtHandle(parse_response(resp)?.handle);
813
814 let op_code = next_op_code(resp)?;
816 if op_code != WireOp::Response as u32 {
817 return err_conn_rejected(op_code);
818 }
819
820 Ok((stmt_handle, parse_response(resp)?.data))
821 },
822 )?;
823
824 let mut xsqlda = Vec::new();
828
829 let PrepareInfo {
830 stmt_type,
831 mut param_count,
832 mut truncated,
833 } = parse_xsqlda(&mut prepare_data, &mut xsqlda)?;
834
835 while truncated {
836 let next_index = (xsqlda.len() as u16).to_le_bytes();
838
839 self.socket.write_all(&info_sql(
840 stmt_handle.0,
841 &[
842 &[
843 ibase::isc_info_sql_sqlda_start as u8, 2,
845 next_index[0], next_index[1], ],
848 &XSQLDA_DESCRIBE_VARS[..], ]
850 .concat(),
851 ))?;
852 self.socket.flush()?;
853
854 let mut data = self.read_response()?.data;
855
856 let parse_resp = parse_xsqlda(&mut data, &mut xsqlda)?;
857 truncated = parse_resp.truncated;
858 param_count = parse_resp.param_count;
859 }
860
861 for var in xsqlda.iter_mut() {
863 var.coerce()?;
864 }
865 let blr = xsqlda_to_blr(&xsqlda)?;
866
867 Ok((
868 stmt_type,
869 StmtHandleData {
870 handle: stmt_handle,
871 xsqlda,
872 blr,
873 param_count,
874 prefetched: VecDeque::new(),
875 cursor_eof: false,
876 },
877 ))
878 }
879
880 pub fn free_statement(
882 &mut self,
883 stmt_handle: &mut StmtHandleData,
884 op: FreeStmtOp,
885 ) -> Result<(), FbError> {
886 self.socket
887 .write_all(&free_statement(stmt_handle.handle.0, op))?;
888 self.lazy_count += 1;
891
892 Ok(())
893 }
894
895 pub fn execute(
897 &mut self,
898 tr_handle: &mut TrHandle,
899 stmt_handle: &mut StmtHandleData,
900 params: &[SqlType],
901 ) -> Result<usize, FbError> {
902 if params.len() != stmt_handle.param_count {
903 return Err(format!(
904 "Tried to execute a statement that has {} parameters while providing {}",
905 stmt_handle.param_count,
906 params.len()
907 )
908 .into());
909 }
910
911 stmt_handle.prefetched.clear();
915 stmt_handle.cursor_eof = false;
916
917 let params = blr::params_to_blr(self, tr_handle, params)?;
919
920 self.socket.write_all(&execute(
921 tr_handle.0,
922 stmt_handle.handle.0,
923 ¶ms.blr,
924 ¶ms.values,
925 ))?;
926 self.socket.flush()?;
927
928 self.read_response()?;
929
930 self.socket.write_all(&info_sql(
932 stmt_handle.handle.0,
933 &[ibase::isc_info_sql_records as u8], ))?;
935 self.socket.flush()?;
936
937 let mut data = self.read_response()?.data;
938
939 parse_info_sql_affected_rows(&mut data)
940 }
941
942 pub fn execute2(
944 &mut self,
945 tr_handle: &mut TrHandle,
946 stmt_handle: &mut StmtHandleData,
947 params: &[SqlType],
948 ) -> Result<Vec<Column>, FbError> {
949 if params.len() != stmt_handle.param_count {
950 return Err(format!(
951 "Tried to execute a statement that has {} parameters while providing {}",
952 stmt_handle.param_count,
953 params.len()
954 )
955 .into());
956 }
957
958 stmt_handle.prefetched.clear();
961 stmt_handle.cursor_eof = false;
962
963 let params = blr::params_to_blr(self, tr_handle, params)?;
964
965 self.socket.write_all(&execute2(
966 tr_handle.0,
967 stmt_handle.handle.0,
968 ¶ms.blr,
969 ¶ms.values,
970 &stmt_handle.blr,
971 ))?;
972 self.socket.flush()?;
973
974 let version = self.version;
975 let charset = self.charset.clone();
976 let xsqlda = &stmt_handle.xsqlda;
977
978 let parsed_cols = read_with(
979 &mut self.socket,
980 &mut self.buff,
981 &mut self.pending,
982 &mut self.lazy_count,
983 |resp, lazy_count| {
984 let op_code = skip_lazy_responses(resp, lazy_count)?;
985
986 if op_code == WireOp::Response as u32 {
987 parse_response(resp)?;
989 }
990
991 if op_code != WireOp::SqlResponse as u32 {
992 return err_conn_rejected(op_code);
993 }
994
995 let parsed_cols = parse_sql_response(resp, xsqlda, version, &charset)?;
996
997 parse_response(resp)?;
998
999 Ok(parsed_cols)
1000 },
1001 )?;
1002
1003 let mut cols = Vec::with_capacity(parsed_cols.len());
1007
1008 for pc in parsed_cols {
1009 cols.push(pc.into_column(self, tr_handle)?);
1010 }
1011
1012 Ok(cols)
1013 }
1014
1015 pub fn fetch(
1020 &mut self,
1021 tr_handle: &mut TrHandle,
1022 stmt_handle: &mut StmtHandleData,
1023 ) -> Result<Option<Vec<Column>>, FbError> {
1024 let count = fetch_batch_size();
1025 let mut empty_batches = 0u32;
1026 while stmt_handle.prefetched.is_empty() && !stmt_handle.cursor_eof {
1027 self.fetch_batch(tr_handle, stmt_handle, count)?;
1028 empty_batches += 1;
1029 if empty_batches > 1000 {
1032 return Err("fetch: too many empty batches without end of cursor".into());
1033 }
1034 }
1035 Ok(stmt_handle.prefetched.pop_front())
1036 }
1037
1038 fn fetch_batch(
1041 &mut self,
1042 tr_handle: &mut TrHandle,
1043 stmt_handle: &mut StmtHandleData,
1044 count: u32,
1045 ) -> Result<(), FbError> {
1046 self.socket
1047 .write_all(&fetch(stmt_handle.handle.0, &stmt_handle.blr, count))?;
1048 self.socket.flush()?;
1049
1050 let version = self.version;
1051 let charset = self.charset.clone();
1052 let xsqlda = &stmt_handle.xsqlda;
1053
1054 let mut rows: Vec<Vec<ParsedColumn>> = Vec::new();
1058 let mut cursor_eof = false;
1059 let mut got = 0u32;
1060
1061 loop {
1062 let one = read_with(
1063 &mut self.socket,
1064 &mut self.buff,
1065 &mut self.pending,
1066 &mut self.lazy_count,
1067 |resp, lazy_count| {
1068 parse_one_fetch_response(resp, lazy_count, xsqlda, version, &charset)
1069 },
1070 )?;
1071
1072 match one {
1073 FetchOne::Row(cols) => {
1074 rows.push(cols);
1075 got += 1;
1076 if got > count {
1082 return Err("server sent more rows than requested in op_fetch".into());
1083 }
1084 }
1085 FetchOne::BatchEnd => break,
1088 FetchOne::End => {
1089 cursor_eof = true;
1090 break;
1091 }
1092 }
1093 }
1094
1095 stmt_handle.cursor_eof = cursor_eof;
1096
1097 for parsed in rows {
1098 let mut cols = Vec::with_capacity(parsed.len());
1099 for pc in parsed {
1100 cols.push(pc.into_column(self, tr_handle)?);
1101 }
1102 stmt_handle.prefetched.push_back(cols);
1103 }
1104
1105 Ok(())
1106 }
1107
1108 pub fn create_blob(
1110 &mut self,
1111 tr_handle: &mut TrHandle,
1112 ) -> Result<(BlobHandle, BlobId), FbError> {
1113 self.socket.write_all(&create_blob(tr_handle.0))?;
1114 self.socket.flush()?;
1115
1116 let resp = self.read_response()?;
1117
1118 Ok((BlobHandle(resp.handle), BlobId(resp.object_id)))
1119 }
1120
1121 pub fn put_segments(&mut self, blob_handle: BlobHandle, data: &[u8]) -> Result<(), FbError> {
1123 for segment in data.chunks(crate::blr::MAX_DATA_LENGTH) {
1124 self.socket
1125 .write_all(&put_segment(blob_handle.0, segment))?;
1126 self.socket.flush()?;
1127
1128 self.read_response()?;
1129 }
1130
1131 Ok(())
1132 }
1133
1134 pub fn open_blob(
1136 &mut self,
1137 tr_handle: &mut TrHandle,
1138 blob_id: BlobId,
1139 ) -> Result<BlobHandle, FbError> {
1140 self.socket.write_all(&open_blob(tr_handle.0, blob_id.0))?;
1141 self.socket.flush()?;
1142
1143 let resp = self.read_response()?;
1144
1145 Ok(BlobHandle(resp.handle))
1146 }
1147
1148 pub fn get_segment(&mut self, blob_handle: BlobHandle) -> Result<(Bytes, bool), FbError> {
1150 self.socket.write_all(&get_segment(blob_handle.0))?;
1151 self.socket.flush()?;
1152
1153 let mut blob_data = BytesMut::with_capacity(256);
1154
1155 let resp = self.read_response()?;
1156 let mut data = resp.data;
1157
1158 loop {
1159 if data.remaining() < 2 {
1160 break;
1161 }
1162 let len = data.get_u16_le()? as usize;
1163 if data.remaining() < len {
1164 return err_invalid_response();
1165 }
1166 blob_data.put_slice(&data[..len]);
1167 data.advance(len)?;
1168 }
1169
1170 Ok((blob_data.freeze(), resp.handle == 2))
1171 }
1172
1173 pub fn close_blob(&mut self, blob_handle: BlobHandle) -> Result<(), FbError> {
1175 self.socket.write_all(&close_blob(blob_handle.0))?;
1176 self.socket.flush()?;
1177
1178 self.read_response()?;
1179
1180 Ok(())
1181 }
1182
1183 fn read_response(&mut self) -> Result<Response, FbError> {
1185 read_response(
1186 &mut self.socket,
1187 &mut self.buff,
1188 &mut self.pending,
1189 &mut self.lazy_count,
1190 )
1191 }
1192}
1193
1194fn read_with<T>(
1207 socket: &mut impl Read,
1208 buff: &mut [u8],
1209 pending: &mut Bytes,
1210 lazy_count: &mut u32,
1211 mut parse: impl FnMut(&mut Bytes, &mut u32) -> Result<T, FbError>,
1212) -> Result<T, FbError> {
1213 loop {
1214 let mut view = pending.clone();
1216 let saved_lazy = *lazy_count;
1217
1218 match parse(&mut view, lazy_count) {
1219 Ok(parsed) => {
1220 *pending = view;
1222 return Ok(parsed);
1223 }
1224
1225 Err(e) if is_incomplete(&e) => {
1226 *lazy_count = saved_lazy;
1228
1229 let len = socket.read(buff)?;
1230 if len == 0 {
1231 return Err("Connection closed by the server".into());
1232 }
1233
1234 let mut next = BytesMut::with_capacity(pending.len() + len);
1235 next.put_slice(pending);
1236 next.put_slice(&buff[..len]);
1237 *pending = next.freeze();
1238 }
1239
1240 Err(e) => {
1244 *pending = view;
1245 return Err(e);
1246 }
1247 }
1248 }
1249}
1250
1251fn next_op_code(resp: &mut Bytes) -> Result<u32, FbError> {
1253 loop {
1254 let op_code = resp.get_u32()?;
1255
1256 if op_code != WireOp::Dummy as u32 {
1257 return Ok(op_code);
1258 }
1259 }
1260}
1261
1262fn skip_lazy_responses(resp: &mut Bytes, lazy_count: &mut u32) -> Result<u32, FbError> {
1264 let mut op_code = next_op_code(resp)?;
1265
1266 while *lazy_count > 0 {
1267 if op_code != WireOp::Response as u32 {
1268 return err_conn_rejected(op_code);
1269 }
1270 *lazy_count -= 1;
1271 parse_response(resp)?;
1272
1273 op_code = next_op_code(resp)?;
1274 }
1275
1276 Ok(op_code)
1277}
1278
1279fn parse_one_fetch_response(
1282 resp: &mut Bytes,
1283 lazy_count: &mut u32,
1284 xsqlda: &[XSqlVar],
1285 version: ProtocolVersion,
1286 charset: &Charset,
1287) -> Result<FetchOne, FbError> {
1288 let op_code = skip_lazy_responses(resp, lazy_count)?;
1289
1290 if op_code == WireOp::Response as u32 {
1291 parse_response(resp)?;
1293 }
1294
1295 if op_code != WireOp::FetchResponse as u32 {
1296 return Err(format!("unexpected op_code in fetch (op {})", op_code).into());
1297 }
1298
1299 if resp.remaining() < 8 {
1303 return err_invalid_response();
1304 }
1305 let (status, messages) = {
1306 let mut peek = resp.clone();
1307 (peek.get_u32()?, peek.get_u32()?)
1308 };
1309
1310 if status == 100 {
1311 resp.advance(8)?;
1316 return Ok(FetchOne::End);
1317 }
1318
1319 if messages == 0 {
1320 resp.advance(8)?;
1322 return Ok(FetchOne::BatchEnd);
1323 }
1324
1325 match parse_fetch_response(resp, xsqlda, version, charset)? {
1327 Some(parsed) => Ok(FetchOne::Row(parsed)),
1328 None => Ok(FetchOne::End),
1329 }
1330}
1331
1332fn read_response(
1334 socket: &mut impl Read,
1335 buff: &mut [u8],
1336 pending: &mut Bytes,
1337 lazy_count: &mut u32,
1338) -> Result<Response, FbError> {
1339 read_with(socket, buff, pending, lazy_count, |resp, lazy_count| {
1340 let op_code = skip_lazy_responses(resp, lazy_count)?;
1341
1342 if op_code != WireOp::Response as u32 {
1343 return err_conn_rejected(op_code);
1344 }
1345
1346 parse_response(resp)
1347 })
1348}
1349
1350pub(crate) fn srp_verifier<D>(
1351 srp: SrpClient<D>,
1352 user: &str,
1353 pass: &str,
1354 data: &SrpAuthData,
1355) -> Result<SrpClientVerifier<D>, FbError>
1356where
1357 D: digest::Digest,
1358{
1359 let private_key = srp_private_key::<sha1::Sha1>(user.as_bytes(), pass.as_bytes(), &data.salt);
1361
1362 let verifier = srp
1364 .process_reply(user.as_bytes(), &data.salt, &private_key, &data.pub_key)
1365 .map_err(|e| FbError::from(format!("Srp error: {}", e)))?;
1366
1367 Ok(verifier)
1369}
1370
1371fn srp_auth<D>(
1373 mut socket: FbStream,
1374 buff: &mut [u8],
1375 pending: &mut Bytes,
1376 srp: SrpClient<D>,
1377 plugin: AuthPluginType,
1378 user: &str,
1379 pass: &str,
1380 data: &SrpAuthData,
1381) -> Result<FbStream, FbError>
1382where
1383 D: digest::Digest,
1384{
1385 let verifier = srp_verifier(srp, user, pass, data)?;
1386
1387 let proof = hex::encode(verifier.get_proof());
1389
1390 socket.write_all(&cont_auth(
1392 proof.as_bytes(),
1393 plugin,
1394 AuthPluginType::plugin_list(),
1395 &[],
1396 ))?;
1397 socket.flush()?;
1398
1399 read_response(&mut socket, buff, pending, &mut 0)?;
1400
1401 socket.write_all(&crypt("Arc4", "Symmetric"))?;
1403 socket.flush()?;
1404
1405 socket = FbStream::Arc4(Arc4Stream::new(
1406 match socket {
1407 FbStream::Plain(s) => s,
1408 _ => unreachable!("Stream was already encrypted!"),
1409 },
1410 &verifier.get_key(),
1411 buff.len(),
1412 ));
1413
1414 read_response(&mut socket, buff, pending, &mut 0)?;
1415
1416 Ok(socket)
1417}
1418
1419#[derive(Debug, Clone, Copy)]
1420pub struct DbHandle(u32);
1422
1423#[derive(Debug, Clone, Copy)]
1424pub struct TrHandle(u32);
1426
1427#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
1428pub struct StmtHandle(u32);
1430
1431#[derive(Debug, Clone, Copy)]
1432pub struct BlobHandle(u32);
1434
1435#[derive(Debug, Clone, Copy)]
1436pub struct BlobId(pub(crate) u64);
1438
1439enum FbStream {
1441 Plain(TcpStream),
1443
1444 Arc4(Arc4Stream<TcpStream>),
1446}
1447
1448impl FbStream {
1449 fn peer_addr(&self) -> std::io::Result<SocketAddr> {
1451 match self {
1452 FbStream::Plain(s) => s.peer_addr(),
1453 FbStream::Arc4(s) => s.peer_addr(),
1454 }
1455 }
1456}
1457
1458impl Read for FbStream {
1459 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1460 match self {
1461 FbStream::Plain(s) => s.read(buf),
1462 FbStream::Arc4(s) => s.read(buf),
1463 }
1464 }
1465}
1466
1467impl Write for FbStream {
1468 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
1469 match self {
1470 FbStream::Plain(s) => s.write(buf),
1471 FbStream::Arc4(s) => s.write(buf),
1472 }
1473 }
1474
1475 fn flush(&mut self) -> std::io::Result<()> {
1476 match self {
1477 FbStream::Plain(s) => s.flush(),
1478 FbStream::Arc4(s) => s.flush(),
1479 }
1480 }
1481}
1482
1483#[cfg(test)]
1484mod read_tests {
1485 use super::*;
1486 use rsfbclient_core::charset::UTF_8;
1487
1488 struct Chunked {
1491 data: Vec<u8>,
1492 pos: usize,
1493 chunk: usize,
1494 }
1495
1496 impl Read for Chunked {
1497 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1498 let n = self.chunk.min(buf.len()).min(self.data.len() - self.pos);
1499 buf[..n].copy_from_slice(&self.data[self.pos..self.pos + n]);
1500 self.pos += n;
1501 Ok(n)
1502 }
1503 }
1504
1505 fn op_response(handle: u32) -> Vec<u8> {
1507 let mut b = BytesMut::new();
1508 b.put_u32(WireOp::Response as u32);
1509 b.put_u32(handle);
1510 b.put_u64(0); b.put_wire_bytes(&[]); b.put_u32(ibase::isc_arg_end); b.to_vec()
1514 }
1515
1516 fn read_one(data: Vec<u8>, chunk: usize) -> (Result<Response, FbError>, Bytes) {
1517 let mut socket = Chunked {
1518 data,
1519 pos: 0,
1520 chunk,
1521 };
1522 let mut buff = vec![0u8; 2048];
1523 let mut pending = Bytes::new();
1524
1525 let resp = read_response(&mut socket, &mut buff, &mut pending, &mut 0);
1526 (resp, pending)
1527 }
1528
1529 #[test]
1533 fn reassembles_response_split_across_reads() {
1534 let packet = op_response(42);
1535
1536 for chunk in [1, 2, 3, 5, 7, 11, packet.len() - 1] {
1537 let (resp, pending) = read_one(packet.clone(), chunk);
1538 let resp = resp.unwrap_or_else(|e| panic!("chunk {chunk}: {e}"));
1539
1540 assert_eq!(resp.handle, 42, "chunk {chunk}");
1541 assert!(pending.is_empty(), "chunk {chunk}: {} left", pending.len());
1542 }
1543 }
1544
1545 #[test]
1549 fn keeps_surplus_bytes_for_the_next_read() {
1550 let mut data = op_response(1);
1551 data.extend_from_slice(&op_response(2));
1552 let len = data.len();
1553
1554 let mut socket = Chunked {
1555 data,
1556 pos: 0,
1557 chunk: len, };
1559 let mut buff = vec![0u8; 2048];
1560 let mut pending = Bytes::new();
1561
1562 let first = read_response(&mut socket, &mut buff, &mut pending, &mut 0).unwrap();
1563 assert_eq!(first.handle, 1);
1564 assert!(!pending.is_empty(), "second response was dropped");
1565
1566 let second = read_response(&mut socket, &mut buff, &mut pending, &mut 0).unwrap();
1569 assert_eq!(second.handle, 2);
1570 assert!(pending.is_empty());
1571 }
1572
1573 #[test]
1576 fn end_of_cursor_consumes_the_whole_response() {
1577 let mut b = BytesMut::new();
1578 b.put_u32(WireOp::FetchResponse as u32);
1579 b.put_u32(100); b.put_u32(0); let mut resp = b.freeze();
1582
1583 let one = parse_one_fetch_response(&mut resp, &mut 0, &[], ProtocolVersion::V13, &UTF_8)
1584 .unwrap_or_else(|e| panic!("{e}"));
1585
1586 assert!(matches!(one, FetchOne::End));
1587 assert!(
1588 resp.is_empty(),
1589 "{} bytes left for the next operation to trip over",
1590 resp.len()
1591 );
1592 }
1593}
1594
1595#[test]
1596#[ignore]
1597fn connection_test() {
1598 use rsfbclient_core::charset::UTF_8;
1599
1600 let db_name = "test.fdb";
1601 let user = "SYSDBA";
1602 let pass = "masterkey";
1603
1604 let mut conn =
1605 FirebirdWireConnection::connect("127.0.0.1", 3050, db_name, user, pass, UTF_8).unwrap();
1606
1607 let mut db_handle = conn
1608 .attach_database(db_name, user, pass, None, Dialect::D3, false)
1609 .unwrap();
1610
1611 let mut tr_handle = conn
1612 .begin_transaction(&mut db_handle, TransactionConfiguration::default())
1613 .unwrap();
1614
1615 let (stmt_type, mut stmt_handle) = conn
1616 .prepare_statement(
1617 &mut db_handle,
1618 &mut tr_handle,
1619 Dialect::D3,
1620 "
1621 SELECT
1622 1, 'abcdefghij' as tst, rand(), CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, -1, -2, -3, -4, -5, 1, 2, 3, 4, 5, 0 as last
1623 FROM RDB$DATABASE where 1 = ?
1624 ",
1625 )
1633 .unwrap();
1634
1635 println!("Statement type: {:?}", stmt_type);
1636
1637 let params = match rsfbclient_core::IntoParams::to_params((1,)) {
1638 rsfbclient_core::ParamsType::Positional(params) => params,
1639 _ => unreachable!(),
1640 };
1641
1642 conn.execute(&mut tr_handle, &mut stmt_handle, ¶ms)
1643 .unwrap();
1644
1645 loop {
1646 let resp = conn.fetch(&mut tr_handle, &mut stmt_handle).unwrap();
1647
1648 if resp.is_none() {
1649 break;
1650 }
1651 println!("Fetch Resp: {:#?}", resp);
1652 }
1653
1654 std::thread::sleep(std::time::Duration::from_millis(100));
1655}