1use std::io::{BufReader, BufWriter};
19use std::path::{Path, PathBuf};
20use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
21use std::sync::mpsc::{Receiver, Sender};
22use std::sync::{Arc, Mutex, OnceLock};
23
24use arrow::array::RecordBatch;
25use arrow::datatypes::SchemaRef;
26use serde_json::{Map, Value};
27
28use crate::frame::{self, Frame, FrameError};
29use crate::msg::{ConnectionField, Envelope, LogLevel, Request, Response, ResultSetMeta};
30use crate::options::{self, OptionField};
31use crate::{CAP_VALIDATE, Kind, MAX_VERSION, MIN_VERSION, PluginId};
32
33pub type Error = Box<dyn std::error::Error + Send + Sync>;
34pub type Result<T> = std::result::Result<T, Error>;
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum ErrorKind {
39 Config,
41 Plugin,
43 Refused,
45 Connection,
47 Auth,
49 Query,
51 Delivery,
53 Internal,
55 Cancelled,
56 TimedOut,
57}
58
59impl ErrorKind {
60 pub fn as_str(self) -> &'static str {
61 match self {
62 ErrorKind::Config => "config",
63 ErrorKind::Plugin => "plugin",
64 ErrorKind::Refused => "refused",
65 ErrorKind::Connection => "connection",
66 ErrorKind::Auth => "auth",
67 ErrorKind::Query => "query",
68 ErrorKind::Delivery => "delivery",
69 ErrorKind::Internal => "internal",
70 ErrorKind::Cancelled => "cancelled",
71 ErrorKind::TimedOut => "timed_out",
72 }
73 }
74}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct PluginError {
80 pub kind: ErrorKind,
81 pub code: Option<String>,
82 pub message: String,
83}
84
85impl PluginError {
86 pub fn new(kind: ErrorKind, message: impl Into<String>) -> PluginError {
87 PluginError {
88 kind,
89 code: None,
90 message: message.into(),
91 }
92 }
93
94 #[must_use]
95 pub fn code(mut self, code: impl Into<String>) -> PluginError {
96 self.code = Some(code.into());
97 self
98 }
99}
100
101impl std::fmt::Display for PluginError {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 f.write_str(&self.message)
104 }
105}
106
107impl std::error::Error for PluginError {}
108
109struct Shared {
112 out: Mutex<BufWriter<Box<dyn std::io::Write + Send>>>,
113 version: AtomicU32,
115 current: AtomicU64,
117 cancelled: AtomicU64,
119 hook: Mutex<Option<CancelHook>>,
120 name: OnceLock<String>,
122}
123
124type CancelHook = Arc<dyn Fn() + Send + Sync>;
125
126fn shared() -> &'static Shared {
127 static SHARED: OnceLock<Shared> = OnceLock::new();
128 SHARED.get_or_init(|| Shared {
129 out: Mutex::new(BufWriter::new(protocol_out())),
130 version: AtomicU32::new(0),
131 current: AtomicU64::new(0),
132 cancelled: AtomicU64::new(0),
133 hook: Mutex::new(None),
134 name: OnceLock::new(),
135 })
136}
137
138fn protocol_out() -> Box<dyn std::io::Write + Send> {
142 #[cfg(unix)]
143 {
144 use std::os::fd::FromRawFd;
145 unsafe {
147 let fd = libc::dup(1);
148 if fd >= 0 && libc::dup2(2, 1) >= 0 {
149 return Box::new(std::fs::File::from_raw_fd(fd));
150 }
151 }
152 }
153 #[cfg(windows)]
154 {
155 use std::os::windows::io::FromRawHandle;
156 use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE;
157 use windows_sys::Win32::System::Console::{
158 GetStdHandle, STD_ERROR_HANDLE, STD_OUTPUT_HANDLE, SetStdHandle,
159 };
160 unsafe {
163 let out = GetStdHandle(STD_OUTPUT_HANDLE);
164 let err = GetStdHandle(STD_ERROR_HANDLE);
165 if !out.is_null() && out != INVALID_HANDLE_VALUE && SetStdHandle(STD_OUTPUT_HANDLE, err) != 0 {
166 return Box::new(std::fs::File::from_raw_handle(out as _));
167 }
168 }
169 }
170 Box::new(std::io::stdout())
171}
172
173pub fn cancelled() -> bool {
175 let s = shared();
176 let current = s.current.load(Ordering::SeqCst);
177 current != 0 && s.cancelled.load(Ordering::SeqCst) == current
178}
179
180pub fn on_cancel(hook: impl Fn() + Send + Sync + 'static) {
188 *shared().hook.lock().unwrap() = Some(Arc::new(hook));
189}
190
191fn cancel(id: u64) {
194 let s = shared();
195 s.cancelled.store(id, Ordering::SeqCst);
196 if id != 0 && s.current.load(Ordering::SeqCst) == id {
197 let hook = s.hook.lock().unwrap().clone();
198 if let Some(hook) = hook {
199 hook();
200 }
201 }
202}
203
204pub fn log_fields(level: LogLevel, message: &str, fields: Map<String, Value>) {
206 let s = shared();
207 if s.version.load(Ordering::SeqCst) == 0 {
208 let prefix = match level {
210 LogLevel::Error | LogLevel::Warn => "warning: ",
211 LogLevel::Info => "info: ",
212 LogLevel::Debug | LogLevel::Trace => "",
213 };
214 eprintln!("{prefix}{message}");
215 return;
216 }
217 send(&Response::Log {
218 level,
219 message: message.to_string(),
220 fields,
221 });
222}
223
224pub fn log(level: LogLevel, message: &str) {
226 log_fields(level, message, Map::new())
227}
228
229pub fn progress(message: Option<&str>, done: Option<u64>, total: Option<u64>) {
231 if shared().version.load(Ordering::SeqCst) == 0 {
232 if let Some(m) = message {
233 log(LogLevel::Info, m);
234 }
235 return;
236 }
237 send(&Response::Progress {
238 message: message.map(str::to_string),
239 done,
240 total,
241 });
242}
243
244struct FrameLogger;
246
247impl ::log::Log for FrameLogger {
248 fn enabled(&self, m: &::log::Metadata) -> bool {
251 m.level() <= ::log::Level::Info || (m.level() <= ::log::Level::Debug && m.target().starts_with("dre"))
252 }
253
254 fn log(&self, r: &::log::Record) {
255 if !self.enabled(r.metadata()) {
256 return;
257 }
258 let level = match r.level() {
259 ::log::Level::Error => LogLevel::Error,
260 ::log::Level::Warn => LogLevel::Warn,
261 ::log::Level::Info => LogLevel::Info,
262 ::log::Level::Debug => LogLevel::Debug,
263 ::log::Level::Trace => LogLevel::Trace,
264 };
265 let level = if r.target().starts_with("dre") {
267 level
268 } else {
269 level.max(LogLevel::Debug)
270 };
271 log(level, &r.args().to_string());
272 }
273
274 fn flush(&self) {}
275}
276
277fn send(r: &Response) {
279 let s = shared();
280 let id = match s.version.load(Ordering::SeqCst) {
281 0 => None,
282 _ => Some(s.current.load(Ordering::SeqCst)).filter(|id| *id != 0),
283 };
284 let mut out = s.out.lock().unwrap();
285 if frame::write_json(&mut *out, &Envelope::new(id, r)).is_err() {
286 std::process::exit(1);
288 }
289}
290
291fn error_reply(e: &Error) -> Response {
294 if cancelled() {
295 return Response::Error {
296 message: e.to_string(),
297 kind: Some("cancelled".into()),
298 code: None,
299 };
300 }
301 match e.downcast_ref::<PluginError>() {
302 Some(pe) => Response::Error {
303 message: pe.message.clone(),
304 kind: Some(pe.kind.as_str().into()),
305 code: pe.code.as_ref().map(|c| match shared().name.get() {
306 Some(name) if !c.contains('/') => format!("{name}/{c}"),
307 _ => c.clone(),
308 }),
309 },
310 None => Response::error(e.to_string()),
311 }
312}
313
314#[derive(Debug, Clone)]
316pub struct About {
317 pub name: &'static str,
318 pub version: &'static str,
319 pub capabilities: &'static [&'static str],
320}
321
322impl About {
323 pub fn new(name: &'static str, version: &'static str) -> About {
325 let version = if version == "0.0.0" { "unreleased" } else { version };
326 About {
327 name,
328 version,
329 capabilities: &[],
330 }
331 }
332
333 #[must_use]
334 pub fn capabilities(mut self, caps: &'static [&'static str]) -> About {
335 self.capabilities = caps;
336 self
337 }
338}
339
340pub trait ResultSink {
343 fn no_result(&mut self, rows_affected: Option<u64>) -> Result<()>;
344 fn begin(&mut self, schema: SchemaRef) -> Result<()>;
345 fn batch(&mut self, batch: RecordBatch) -> Result<bool>;
347}
348
349pub trait Source {
350 fn connection_fields(&self) -> Vec<ConnectionField> {
351 Vec::new()
352 }
353 fn identifier_quote(&self) -> Option<&'static str> {
356 None
357 }
358 fn string_literal(&self) -> Option<&'static str> {
362 None
363 }
364 fn single_writer(&self) -> Option<crate::msg::SingleWriter> {
368 None
369 }
370 fn validate_connection(&self, _connection: &Map<String, Value>) -> Vec<String> {
375 Vec::new()
376 }
377 fn open(&mut self, connection: &Map<String, Value>, read_only: bool) -> Result<()>;
378 fn open_sandboxed(&mut self, connection: &Map<String, Value>) -> Result<()> {
381 self.open(connection, true)
382 }
383 fn execute(&mut self, sql: &str, row_limit: Option<u64>, out: &mut dyn ResultSink) -> Result<()>;
385 fn check(&mut self, _sql: &str) -> Result<()> {
387 Err("this source can't check statements".into())
388 }
389 fn load(&mut self, _name: &str, _data: &mut ResultSet<'_>) -> Result<Loaded> {
392 Err("this source can't load rows".into())
393 }
394 fn catalog(&mut self, _tables: &[String], _schemas: &[String]) -> Result<Value> {
397 Err("this source can't discover catalogue metadata".into())
398 }
399 fn close(&mut self) {}
401}
402
403pub struct Loaded {
405 pub relation: String,
407 pub rows: u64,
408 pub warning: Option<String>,
410}
411
412pub struct ResultSet<'a> {
414 pub meta: ResultSetMeta,
415 pub schema: SchemaRef,
416 first: Option<Vec<RecordBatch>>,
417 input: &'a mut Input,
418 done: bool,
419}
420
421impl ResultSet<'_> {
422 pub fn next_batch(&mut self) -> Result<Option<RecordBatch>> {
424 loop {
425 if let Some(first) = self.first.as_mut() {
426 if !first.is_empty() {
427 return Ok(Some(first.remove(0)));
428 }
429 self.first = None;
430 }
431 if self.done {
432 return Ok(None);
433 }
434 match self.input.read()? {
435 Frame::Arrow(ipc) => {
436 let (_, batches) = frame::decode_batches(&ipc)?;
437 self.first = Some(batches);
438 }
439 Frame::Json(v) => match serde_json::from_value::<Request>(v)? {
440 Request::ResultSetEnd {} => {
441 self.done = true;
442 return Ok(None);
443 }
444 other => return Err(format!("expected result data, got {other:?}").into()),
445 },
446 }
447 }
448 }
449
450 fn drain(&mut self) -> Result<()> {
451 while self.next_batch()?.is_some() {}
452 Ok(())
453 }
454}
455
456pub struct WriteRequest {
458 pub path: String,
459 pub format: String,
460 pub options: Map<String, Value>,
461 pub result_sets: Vec<ResultSetMeta>,
462 pub template: Option<Value>,
463 pub font_requests: bool,
464}
465
466pub struct ResultSets<'a> {
468 metas: std::vec::IntoIter<ResultSetMeta>,
469 input: &'a mut Input,
470 warnings: Vec<String>,
471 finished: bool,
472}
473
474impl ResultSets<'_> {
475 pub fn warn(&mut self, message: impl Into<String>) {
477 self.warnings.push(message.into());
478 }
479
480 pub fn request_fonts(
484 &mut self,
485 font: crate::msg::FontRequest,
486 ) -> Result<std::result::Result<Vec<String>, crate::msg::FontError>> {
487 if self.metas.len() != 0 {
488 return Err("read all result sets before requesting fonts".into());
489 }
490 if !self.finished {
491 match self.input.read()? {
492 Frame::Json(v) if v.get("type").and_then(Value::as_str) == Some("finish") => {}
493 other => return Err(format!("expected finish before font request, got {other:?}").into()),
494 }
495 self.finished = true;
496 }
497 send(&Response::NeedFonts { font });
498 match self.input.read()? {
499 Frame::Json(v) => match serde_json::from_value::<crate::msg::Envelope<Request>>(v)?.body {
500 Request::Fonts {
501 paths, error: None, ..
502 } => Ok(Ok(paths)),
503 Request::Fonts {
504 error: Some(message),
505 repeated,
506 ..
507 } => Ok(Err(crate::msg::FontError { message, repeated })),
508 other => Err(format!("expected font paths, got {other:?}").into()),
509 },
510 other => Err(format!("expected font paths, got {other:?}").into()),
511 }
512 }
513
514 pub fn next_set(&mut self) -> Result<Option<ResultSet<'_>>> {
517 let Some(meta) = self.metas.next() else {
518 return Ok(None);
519 };
520 let ipc = match self.input.read()? {
521 Frame::Arrow(ipc) => ipc,
522 Frame::Json(v) => {
523 return Err(format!(
524 "expected an Arrow frame starting result set `{}`, got {v}",
525 meta.name
526 )
527 .into());
528 }
529 };
530 let (schema, batches) = frame::decode_batches(&ipc)?;
531 Ok(Some(ResultSet {
532 meta,
533 schema,
534 first: Some(batches),
535 input: &mut *self.input,
536 done: false,
537 }))
538 }
539}
540
541pub trait Format {
542 fn options(&self) -> Vec<OptionField> {
545 Vec::new()
546 }
547 fn validate(&self, _options: &Map<String, Value>) -> Vec<String> {
550 Vec::new()
551 }
552 fn validate_template(
555 &self,
556 _options: &Map<String, Value>,
557 _template: &Value,
558 ) -> (Vec<String>, Vec<String>) {
559 (Vec::new(), Vec::new())
560 }
561 fn unknown_option_hint(&self, _key: &str) -> Option<String> {
564 None
565 }
566 fn write(&mut self, req: &WriteRequest, sets: &mut ResultSets<'_>) -> Result<Vec<String>>;
569}
570
571pub struct Delivery {
573 pub files: Vec<DeliveryFile>,
576 pub connection: Map<String, Value>,
577 pub options: Map<String, Value>,
579 pub message: Option<crate::msg::Message>,
581}
582
583pub struct DeliveryFile {
585 pub local: PathBuf,
586 pub remote: Option<String>,
587}
588
589pub trait Destination {
590 fn connection_fields(&self) -> Vec<ConnectionField> {
591 Vec::new()
592 }
593 fn options(&self) -> Vec<OptionField> {
597 Vec::new()
598 }
599 fn validate(&self, _options: &Map<String, Value>) -> Vec<String> {
602 Vec::new()
603 }
604 fn validate_connection(&self, _connection: &Map<String, Value>) -> Vec<String> {
608 Vec::new()
609 }
610 fn deliver(
613 &mut self,
614 _local: &Path,
615 _remote: Option<&str>,
616 _connection: &Map<String, Value>,
617 ) -> Result<String> {
618 Err("this destination doesn't implement `deliver`".into())
619 }
620 fn message_limit(&self) -> Option<u64> {
623 None
624 }
625 fn deliver_message(&mut self, _d: &Delivery, _m: &crate::msg::Message) -> Result<String> {
628 Err("this destination doesn't take messages".into())
629 }
630 fn deliver_files(&mut self, d: &Delivery) -> Result<String> {
633 match d.files.as_slice() {
634 [f] => self.deliver(&f.local, f.remote.as_deref(), &d.connection),
635 _ => Err("this destination takes one file per delivery".into()),
636 }
637 }
638}
639
640pub struct Input {
642 rx: Receiver<std::result::Result<Frame, FrameError>>,
643}
644
645impl Input {
646 fn next(&mut self) -> std::result::Result<Frame, FrameError> {
647 self.rx.recv().unwrap_or(Err(FrameError::Eof))
648 }
649
650 fn read(&mut self) -> Result<Frame> {
651 self.next().map_err(|e| -> Error {
652 match e {
653 FrameError::Eof => "core closed the connection".into(),
654 e => e.to_string().into(),
655 }
656 })
657 }
658}
659
660fn read_stdin(tx: Sender<std::result::Result<Frame, FrameError>>) {
663 let mut r = BufReader::new(std::io::stdin());
664 loop {
665 let f = frame::read_frame(&mut r);
666 match &f {
667 Ok(Frame::Json(v)) if v.get("type").and_then(Value::as_str) == Some("cancel") => {
668 cancel(v.get("id").and_then(Value::as_u64).unwrap_or(0));
669 continue;
670 }
671 Err(_) => cancel(shared().current.load(Ordering::SeqCst)),
672 Ok(_) => {}
673 }
674 let stop = f.is_err();
675 if tx.send(f).is_err() || stop {
676 break;
677 }
678 }
679}
680
681struct Output;
683
684impl Output {
685 fn send(&mut self, r: &Response) {
686 send(r)
687 }
688
689 fn batch(&mut self, b: &RecordBatch) -> Result<()> {
690 let ipc = frame::encode_batch(b)?;
691 let mut out = shared().out.lock().unwrap();
692 frame::write_arrow(&mut *out, &ipc).map_err(|_| -> Error { "core closed the connection".into() })
693 }
694}
695
696enum Handler<'a> {
697 Source(&'a mut dyn Source),
698 Format(&'a mut dyn Format),
699 Destination(&'a mut dyn Destination),
700}
701
702impl Handler<'_> {
703 fn kind(&self) -> Kind {
704 match self {
705 Handler::Source(_) => Kind::Source,
706 Handler::Format(_) => Kind::Format,
707 Handler::Destination(_) => Kind::Destination,
708 }
709 }
710
711 fn option_fields(&self) -> Vec<OptionField> {
712 match self {
713 Handler::Source(_) => Vec::new(),
714 Handler::Format(f) => f.options(),
715 Handler::Destination(d) => d.options(),
716 }
717 }
718
719 fn check(&self, name: &str, o: &Map<String, Value>) -> Vec<String> {
722 let mut errs = options::check(self.kind(), name, &self.option_fields(), o);
723 if let Handler::Format(f) = self {
724 for e in &mut errs {
725 let hint = o
726 .keys()
727 .find(|k| e.starts_with(&format!("unknown option `{k}`")))
728 .and_then(|k| f.unknown_option_hint(k));
729 if let Some(h) = hint {
730 e.push_str("; ");
731 e.push_str(&h);
732 }
733 }
734 }
735 if !errs.is_empty() {
736 return errs;
737 }
738 match self {
739 Handler::Source(_) => Vec::new(),
740 Handler::Format(f) => f.validate(o),
741 Handler::Destination(d) => d.validate(o),
742 }
743 }
744
745 fn checked(&self, name: &str, o: &Map<String, Value>) -> Result<()> {
747 let errs = self.check(name, o);
748 if errs.is_empty() {
749 Ok(())
750 } else {
751 Err(PluginError::new(ErrorKind::Config, errs.join("; ")).into())
753 }
754 }
755}
756
757pub fn serve_source(about: About, s: impl Source + 'static) -> ! {
758 serve_package(vec![Plugin::Source(about, Box::new(s))])
759}
760
761pub fn serve_format(about: About, f: impl Format + 'static) -> ! {
762 serve_package(vec![Plugin::Format(about, Box::new(f))])
763}
764
765pub fn serve_destination(about: About, d: impl Destination + 'static) -> ! {
766 serve_package(vec![Plugin::Destination(about, Box::new(d))])
767}
768
769pub enum Plugin {
771 Source(About, Box<dyn Source>),
772 Format(About, Box<dyn Format>),
773 Destination(About, Box<dyn Destination>),
774}
775
776impl Plugin {
777 fn id(&self) -> PluginId {
778 let (kind, about) = match self {
779 Plugin::Source(a, _) => (Kind::Source, a),
780 Plugin::Format(a, _) => (Kind::Format, a),
781 Plugin::Destination(a, _) => (Kind::Destination, a),
782 };
783 PluginId::new(kind, about.name)
784 }
785
786 fn handler(&mut self) -> (&About, Handler<'_>) {
787 match self {
788 Plugin::Source(a, s) => (a, Handler::Source(s.as_mut())),
789 Plugin::Format(a, f) => (a, Handler::Format(f.as_mut())),
790 Plugin::Destination(a, d) => (a, Handler::Destination(d.as_mut())),
791 }
792 }
793}
794
795pub fn serve_package(mut plugins: Vec<Plugin>) -> ! {
802 assert!(!plugins.is_empty(), "a package serves at least one plugin");
803 shared();
805 let (tx, rx) = std::sync::mpsc::channel();
806 std::thread::spawn(move || read_stdin(tx));
807 let mut input = Input { rx };
808 let mut out = Output;
809 if ::log::set_logger(&FrameLogger).is_ok() {
810 ::log::set_max_level(::log::LevelFilter::Debug);
811 }
812 let provides: Vec<PluginId> = plugins.iter().map(Plugin::id).collect();
813 let chosen = loop {
814 let Some(req) = next_request(&mut input, &mut out) else {
815 continue;
816 };
817 let Request::Hello {
818 min_version,
819 max_version,
820 plugin,
821 ..
822 } = req
823 else {
824 out.send(&Response::error("the first request must be `hello`"));
825 continue;
826 };
827 let Some(chosen) = negotiate((min_version, max_version), (MIN_VERSION, MAX_VERSION)) else {
828 out.send(&Response::VersionMismatch {
829 min_version: MIN_VERSION,
830 max_version: MAX_VERSION,
831 });
832 std::process::exit(1);
833 };
834 let i = match &plugin {
835 None => 0,
836 Some(want) => match provides.iter().position(|p| p == want) {
837 Some(i) => i,
838 None => {
839 let list: Vec<String> = provides.iter().map(|p| p.to_string()).collect();
840 out.send(&Response::error(format!(
841 "this executable provides {}, not {want}",
842 list.join(", ")
843 )));
844 std::process::exit(1);
845 }
846 },
847 };
848 let (about, h) = plugins[i].handler();
850 let _ = shared().name.set(about.name.to_string());
851 out.send(&Response::Hello {
852 protocol_version: chosen,
853 kind: h.kind(),
854 name: about.name.to_string(),
855 version: about.version.to_string(),
856 capabilities: about
857 .capabilities
858 .iter()
859 .chain(std::iter::once(&CAP_VALIDATE))
860 .map(|c| c.to_string())
861 .collect(),
862 provides: if provides.len() > 1 { provides } else { Vec::new() },
863 });
864 shared().version.store(chosen, Ordering::SeqCst);
865 break i;
866 };
867 let (about, h) = plugins[chosen].handler();
868 serve(about.name, h, input, out)
869}
870
871fn next_request(input: &mut Input, out: &mut Output) -> Option<Request> {
873 let frame = match input.next() {
874 Ok(f) => f,
875 Err(FrameError::Eof) => std::process::exit(0),
876 Err(e) => {
877 eprintln!("{e}");
878 out.send(&Response::error(e.to_string()));
879 std::process::exit(2);
880 }
881 };
882 match frame {
883 Frame::Json(v) => match serde_json::from_value::<Request>(v.clone()) {
884 Ok(r) => Some(r),
885 Err(_) => {
886 let t = v.get("type").and_then(Value::as_str).unwrap_or("?").to_string();
887 out.send(&Response::error(format!("unsupported request `{t}`")));
888 None
889 }
890 },
891 Frame::Arrow(_) => {
892 out.send(&Response::error("unexpected Arrow frame"));
893 None
894 }
895 }
896}
897
898fn serve(name: &str, mut h: Handler<'_>, mut input: Input, mut out: Output) -> ! {
900 loop {
901 let frame = match input.next() {
902 Ok(f) => f,
903 Err(FrameError::Eof) => {
904 if let Handler::Source(src) = &mut h {
905 src.close();
906 }
907 std::process::exit(0)
908 }
909 Err(e) => {
910 eprintln!("{e}");
911 out.send(&Response::error(e.to_string()));
912 std::process::exit(2);
913 }
914 };
915 let s = shared();
916 let id = match &frame {
917 Frame::Json(v) => v.get("id").and_then(Value::as_u64).unwrap_or(0),
918 Frame::Arrow(_) => 0,
919 };
920 s.current.store(id, Ordering::SeqCst);
921 let req = match frame {
922 Frame::Json(v) => match serde_json::from_value::<Request>(v.clone()) {
923 Ok(r) => r,
924 Err(_) => {
925 let t = v.get("type").and_then(Value::as_str).unwrap_or("?").to_string();
926 out.send(&Response::error(format!("unsupported request `{t}`")));
927 s.current.store(0, Ordering::SeqCst);
928 continue;
929 }
930 },
931 Frame::Arrow(_) => {
932 out.send(&Response::error("unexpected Arrow frame"));
933 continue;
934 }
935 };
936 if let Request::Hello { .. } = req {
937 out.send(&Response::error("`hello` was already answered"));
938 s.current.store(0, Ordering::SeqCst);
939 continue;
940 }
941 if let Request::Close {} = req {
942 if let Handler::Source(src) = &mut h {
943 src.close();
944 }
945 out.send(&Response::Ok {});
946 std::process::exit(0);
947 }
948 let result = if cancelled() {
950 Ok(Err("cancelled before it started".into()))
951 } else {
952 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
955 handle(&mut h, name, req, &mut input, &mut out)
956 }))
957 };
958 match result {
959 Ok(Ok(())) => {}
960 Ok(Err(e)) => out.send(&error_reply(&e)),
961 Err(p) => {
962 let msg = p
963 .downcast_ref::<String>()
964 .cloned()
965 .or_else(|| p.downcast_ref::<&str>().map(|s| s.to_string()))
966 .unwrap_or_else(|| "unknown panic".into());
967 out.send(&Response::Error {
968 message: format!("plugin panicked: {msg}"),
969 kind: Some("internal".into()),
970 code: None,
971 });
972 std::process::exit(101);
973 }
974 }
975 s.current.store(0, Ordering::SeqCst);
976 }
977}
978
979fn check_connection(
982 h: &Handler<'_>,
983 name: &str,
984 connection: &Map<String, Value>,
985 unresolved: &[String],
986) -> Result<crate::connection::Checked> {
987 let (kind, fields) = match h {
988 Handler::Source(s) => (Kind::Source, s.connection_fields()),
989 Handler::Destination(d) => (Kind::Destination, d.connection_fields()),
990 Handler::Format(_) => return Err("a format has no connection settings".into()),
991 };
992 let mut c = crate::connection::check(kind, name, &fields, connection, unresolved);
993 if c.errors.is_empty() {
994 c.errors = match h {
997 Handler::Source(s) => s.validate_connection(connection),
998 Handler::Destination(d) => d.validate_connection(connection),
999 Handler::Format(_) => Vec::new(),
1000 };
1001 }
1002 c.errors = crate::connection::redact(c.errors, &fields, connection);
1003 c.warnings = crate::connection::redact(c.warnings, &fields, connection);
1004 Ok(c)
1005}
1006
1007fn handle(h: &mut Handler<'_>, name: &str, req: Request, input: &mut Input, out: &mut Output) -> Result<()> {
1008 if let Request::Describe {} = req {
1009 let connection_fields = match h {
1010 Handler::Source(s) => s.connection_fields(),
1011 Handler::Destination(d) => d.connection_fields(),
1012 Handler::Format(_) => Vec::new(),
1013 };
1014 let (identifier_quote, string_literal, single_writer) = match h {
1015 Handler::Source(s) => (
1016 s.identifier_quote().map(str::to_string),
1017 s.string_literal().map(str::to_string),
1018 s.single_writer(),
1019 ),
1020 _ => (None, None, None),
1021 };
1022 let message_limit = match h {
1023 Handler::Destination(d) => d.message_limit(),
1024 _ => None,
1025 };
1026 out.send(&Response::Describe {
1027 connection_fields,
1028 option_fields: h.option_fields(),
1029 identifier_quote,
1030 string_literal,
1031 message_limit,
1032 single_writer,
1033 });
1034 return Ok(());
1035 }
1036 if let Request::Validate { options, template } = req {
1037 let mut errors = h.check(name, &options);
1038 let mut warnings = Vec::new();
1039 if let (Handler::Format(f), Some(t), true) = (&*h, &template, errors.is_empty()) {
1040 let (e, w) = f.validate_template(&options, t);
1041 errors.extend(e);
1042 warnings.extend(w);
1043 }
1044 out.send(&Response::Validated { errors, warnings });
1045 return Ok(());
1046 }
1047 if let Request::ValidateConnection {
1048 connection,
1049 unresolved,
1050 } = req
1051 {
1052 let c = check_connection(h, name, &connection, &unresolved)?;
1053 out.send(&Response::Validated {
1054 errors: c.errors,
1055 warnings: c.warnings,
1056 });
1057 return Ok(());
1058 }
1059 if let Request::Open { connection, .. } | Request::Deliver { connection, .. } = &req {
1061 let c = check_connection(h, name, connection, &[])?;
1062 for w in &c.warnings {
1063 crate::log::warn!("{w}");
1064 }
1065 if !c.errors.is_empty() {
1066 return Err(PluginError::new(ErrorKind::Config, c.errors.join("; ")).into());
1067 }
1068 }
1069 let checked = match &req {
1070 Request::Write { options, .. } | Request::Deliver { options, .. } => h.checked(name, options),
1071 _ => Ok(()),
1072 };
1073 match (h, req) {
1074 (
1075 Handler::Source(s),
1076 Request::Open {
1077 connection,
1078 read_only,
1079 sandbox,
1080 },
1081 ) => {
1082 if sandbox {
1083 s.open_sandboxed(&connection)?;
1084 } else {
1085 s.open(&connection, read_only)?;
1086 }
1087 out.send(&Response::Ok {});
1088 }
1089 (Handler::Source(s), Request::Load { name }) => {
1090 let ipc = match input.read()? {
1091 Frame::Arrow(ipc) => ipc,
1092 Frame::Json(v) => return Err(format!("expected the rows to load, got {v}").into()),
1093 };
1094 let (schema, batches) = frame::decode_batches(&ipc)?;
1095 let mut data = ResultSet {
1096 meta: ResultSetMeta {
1097 name: name.clone(),
1098 query: name.clone(),
1099 result_index: 1,
1100 anchor: None,
1101 header: None,
1102 columns: Default::default(),
1103 autofit: None,
1104 style: None,
1105 },
1106 schema,
1107 first: Some(batches),
1108 input,
1109 done: false,
1110 };
1111 let r = s.load(&name, &mut data);
1112 data.drain()?;
1113 let loaded = r?;
1114 out.send(&Response::Loaded {
1115 relation: loaded.relation,
1116 rows: loaded.rows,
1117 warning: loaded.warning,
1118 });
1119 }
1120 (Handler::Source(s), Request::Check { sql }) => {
1121 s.check(&sql)?;
1122 out.send(&Response::Ok {});
1123 }
1124 (Handler::Source(s), Request::Catalog { tables, schemas }) => {
1125 let catalog = s.catalog(&tables, &schemas)?;
1126 out.send(&Response::Catalog { catalog })
1127 }
1128 (Handler::Source(s), Request::Execute { sql, row_limit }) => {
1129 let mut sink = FrameSink {
1130 out,
1131 row_limit,
1132 rows: 0,
1133 state: SinkState::Idle,
1134 schema: None,
1135 sent_any: false,
1136 };
1137 let r = s.execute(&sql, row_limit, &mut sink);
1138 match (r, sink.state) {
1139 (Err(e), _) => return Err(e),
1140 (Ok(()), SinkState::Idle) => {
1141 return Err("the source produced neither a result nor `no_result`".into());
1142 }
1143 (Ok(()), SinkState::NoResult) => {}
1144 (Ok(()), SinkState::Result) => {
1145 if !sink.sent_any {
1146 let schema = sink.schema.clone().expect("a result sets the schema");
1147 sink.out.batch(&RecordBatch::new_empty(schema))?;
1148 }
1149 let rows = sink.rows;
1150 sink.out.send(&Response::ResultEnd { rows });
1151 }
1152 }
1153 }
1154 (
1155 Handler::Format(f),
1156 Request::Write {
1157 path,
1158 format,
1159 options,
1160 result_sets,
1161 template,
1162 font_requests,
1163 },
1164 ) => {
1165 let req = WriteRequest {
1166 path,
1167 format,
1168 options,
1169 result_sets: result_sets.clone(),
1170 template,
1171 font_requests,
1172 };
1173 let mut sets = ResultSets {
1174 metas: result_sets.into_iter(),
1175 input,
1176 warnings: Vec::new(),
1177 finished: false,
1178 };
1179 let written = checked.and_then(|()| f.write(&req, &mut sets));
1180 if let Err(e) = &written {
1183 out.send(&error_reply(e));
1184 }
1185 while !sets.finished {
1188 match sets.input.read()? {
1189 Frame::Json(v) if v.get("type").and_then(Value::as_str) == Some("finish") => break,
1190 Frame::Json(v) if v.get("type").and_then(Value::as_str) == Some("result_set_end") => {}
1191 Frame::Arrow(_) => {}
1192 other => return Err(format!("expected `finish`, got {other:?}").into()),
1193 }
1194 }
1195 if let Ok(files) = written {
1196 out.send(&Response::Written {
1197 files,
1198 warnings: sets.warnings,
1199 });
1200 }
1201 }
1202 (
1203 Handler::Destination(d),
1204 Request::Deliver {
1205 local_path,
1206 remote_path,
1207 files,
1208 connection,
1209 options,
1210 message,
1211 },
1212 ) => {
1213 checked?;
1214 let files = match (local_path, files.is_empty(), &message) {
1215 (Some(local), true, None) => vec![DeliveryFile {
1216 local: PathBuf::from(local),
1217 remote: remote_path,
1218 }],
1219 (None, false, _) | (None, true, Some(_)) => files
1220 .into_iter()
1221 .map(|f| DeliveryFile {
1222 local: PathBuf::from(f.local_path),
1223 remote: f.remote_path,
1224 })
1225 .collect(),
1226 _ => return Err("`deliver` needs exactly one of `local_path` or `files`".into()),
1227 };
1228 let delivery = Delivery {
1229 files,
1230 connection,
1231 options,
1232 message,
1233 };
1234 crate::delivery::take_attempts();
1235 let location = match &delivery.message {
1236 Some(m) => d.deliver_message(&delivery, m)?,
1237 None => d.deliver_files(&delivery)?,
1238 };
1239 let attempts = Some(crate::delivery::take_attempts()).filter(|n| *n > 1);
1240 out.send(&Response::Delivered { location, attempts });
1241 }
1242 (h, req) => {
1243 let t = serde_json::to_value(&req)
1244 .ok()
1245 .and_then(|v| v.get("type").cloned())
1246 .unwrap_or_default();
1247 return Err(format!("a {} plugin doesn't handle {t} requests", h.kind()).into());
1248 }
1249 }
1250 Ok(())
1251}
1252
1253#[derive(PartialEq)]
1254enum SinkState {
1255 Idle,
1256 NoResult,
1257 Result,
1258}
1259
1260struct FrameSink<'a> {
1261 out: &'a mut Output,
1262 row_limit: Option<u64>,
1263 rows: u64,
1264 state: SinkState,
1265 schema: Option<SchemaRef>,
1266 sent_any: bool,
1267}
1268
1269impl ResultSink for FrameSink<'_> {
1270 fn no_result(&mut self, rows_affected: Option<u64>) -> Result<()> {
1271 if self.state != SinkState::Idle {
1272 return Err("`no_result` after the result started".into());
1273 }
1274 self.state = SinkState::NoResult;
1275 self.out.send(&Response::NoResult { rows_affected });
1276 Ok(())
1277 }
1278
1279 fn begin(&mut self, schema: SchemaRef) -> Result<()> {
1280 if self.state != SinkState::Idle {
1281 return Err("a statement can only produce one result".into());
1282 }
1283 self.state = SinkState::Result;
1284 self.out.send(&Response::Result {
1285 columns: schema.fields().iter().map(|f| f.name().clone()).collect(),
1286 });
1287 self.schema = Some(schema);
1288 Ok(())
1289 }
1290
1291 fn batch(&mut self, b: RecordBatch) -> Result<bool> {
1292 if self.state != SinkState::Result {
1293 return Err("`batch` before `begin`".into());
1294 }
1295 if self.row_limit.is_some_and(|l| self.rows >= l) {
1296 return Ok(false);
1297 }
1298 let b = match self.row_limit {
1299 Some(l) if self.rows + b.num_rows() as u64 > l => b.slice(0, (l - self.rows) as usize),
1300 _ => b,
1301 };
1302 if b.num_rows() > 0 || !self.sent_any {
1303 self.rows += b.num_rows() as u64;
1304 self.out.batch(&b)?;
1305 self.sent_any = true;
1306 }
1307 Ok(self.row_limit.is_none_or(|l| self.rows < l))
1308 }
1309}
1310
1311fn negotiate(core: (u32, u32), ours: (u32, u32)) -> Option<u32> {
1313 let (lo, hi) = (core.0.max(ours.0), core.1.min(ours.1));
1314 (lo <= hi).then_some(hi)
1315}
1316
1317pub fn conn_str<'a>(c: &'a Map<String, Value>, key: &str) -> Option<&'a str> {
1319 c.get(key).and_then(Value::as_str).filter(|s| !s.is_empty())
1320}
1321
1322pub fn conn_required<'a>(c: &'a Map<String, Value>, key: &str) -> Result<&'a str> {
1324 conn_str(c, key).ok_or_else(|| format!("the profile output needs a `{key}` field").into())
1325}
1326
1327pub fn conn_bool(c: &Map<String, Value>, key: &str) -> Option<bool> {
1329 match c.get(key)? {
1330 Value::Bool(b) => Some(*b),
1331 Value::String(s) => Some(matches!(s.as_str(), "true" | "yes" | "1")),
1332 _ => None,
1333 }
1334}