1use std::collections::{BTreeMap, BTreeSet};
95use std::fmt;
96use std::io::{ErrorKind, Read, Write};
97use std::net::TcpStream;
98use std::time::{Duration, Instant};
99
100use anyhow::{anyhow, bail};
101use bytes::{BufMut, BytesMut};
102use fallible_iterator::FallibleIterator;
103use mz_ore::collections::CollectionExt;
104use postgres_protocol::IsNull;
105use postgres_protocol::message::backend::Message;
106use postgres_protocol::message::frontend;
107use serde::{Deserialize, Serialize};
108
109struct PgConn {
110 stream: TcpStream,
111 recv_buf: BytesMut,
112 send_buf: BytesMut,
113 timeout: Duration,
114 verbose: bool,
115}
116
117impl PgConn {
118 fn new<'a>(
119 addr: &str,
120 user: &'a str,
121 timeout: Duration,
122 verbose: bool,
123 mut options: Vec<(&'a str, &'a str)>,
124 ) -> anyhow::Result<Self> {
125 let mut conn = Self {
126 stream: TcpStream::connect(addr)?,
127 recv_buf: BytesMut::new(),
128 send_buf: BytesMut::new(),
129 timeout,
130 verbose,
131 };
132
133 conn.stream.set_read_timeout(Some(timeout))?;
134 options.insert(0, ("user", user));
135 options.insert(0, ("welcome_message", "off"));
136 conn.send(|buf| frontend::startup_message(options, buf).unwrap())?;
137 match conn.recv()?.1 {
138 Message::AuthenticationOk => {}
139 _ => bail!("expected AuthenticationOk"),
140 };
141 conn.until(
142 vec!["ReadyForQuery"],
143 vec!['C', 'S', 'M'],
144 BTreeSet::new(),
145 &BTreeSet::new(),
146 )?;
147 Ok(conn)
148 }
149
150 fn send<F: FnOnce(&mut BytesMut)>(&mut self, f: F) -> anyhow::Result<()> {
151 self.send_buf.clear();
152 f(&mut self.send_buf);
153 self.stream.write_all(&self.send_buf)?;
154 Ok(())
155 }
156 fn until(
157 &mut self,
158 until: Vec<&str>,
159 err_field_typs: Vec<char>,
160 ignore: BTreeSet<String>,
161 parameter_status: &BTreeSet<String>,
162 ) -> anyhow::Result<Vec<String>> {
163 let mut msgs = Vec::with_capacity(until.len());
164 for expect in until {
165 loop {
166 let (ch, msg) = match self.recv() {
167 Ok((ch, msg)) => (ch, msg),
168 Err(err) => bail!("{}: waiting for {}, saw {:#?}", err, expect, msgs),
169 };
170 let (typ, args) = match msg {
171 Message::ReadyForQuery(body) => (
172 "ReadyForQuery",
173 serde_json::to_string(&ReadyForQuery {
174 status: char::from(body.status()).to_string(),
175 })?,
176 ),
177 Message::RowDescription(body) => (
178 "RowDescription",
179 serde_json::to_string(&RowDescription {
180 fields: body
181 .fields()
182 .map(|f| {
183 Ok(Field {
184 name: f.name().to_string(),
185 })
186 })
187 .collect()
188 .unwrap(),
189 })?,
190 ),
191 Message::DataRow(body) => {
192 let buf = body.buffer();
193 (
194 "DataRow",
195 serde_json::to_string(&DataRow {
196 fields: body
197 .ranges()
198 .map(|range| {
199 match range {
200 Some(range) => {
201 Ok(String::from_utf8(
203 buf[range.start..range.end].to_vec(),
204 )
205 .unwrap_or_else(|_| {
206 format!(
207 "{:?}",
208 buf[range.start..range.end].to_vec()
209 )
210 }))
211 }
212 None => Ok("NULL".into()),
213 }
214 })
215 .collect()
216 .unwrap(),
217 })?,
218 )
219 }
220 Message::CommandComplete(body) => (
221 "CommandComplete",
222 serde_json::to_string(&CommandComplete {
223 tag: body.tag().unwrap().to_string(),
224 })?,
225 ),
226 Message::ParseComplete => ("ParseComplete", "".to_string()),
227 Message::BindComplete => ("BindComplete", "".to_string()),
228 Message::PortalSuspended => ("PortalSuspended", "".to_string()),
229 Message::ErrorResponse(body) => (
230 "ErrorResponse",
231 serde_json::to_string(&ErrorResponse {
232 fields: body
233 .fields()
234 .filter_map(|f| {
235 let typ = char::from(f.type_());
236 if err_field_typs.contains(&typ) {
237 Ok(Some(ErrorField {
238 typ,
239 value: String::from_utf8_lossy(f.value_bytes())
240 .into_owned(),
241 }))
242 } else {
243 Ok(None)
244 }
245 })
246 .collect()
247 .unwrap(),
248 })?,
249 ),
250 Message::NoticeResponse(body) => (
251 "NoticeResponse",
252 serde_json::to_string(&ErrorResponse {
253 fields: body
254 .fields()
255 .filter_map(|f| {
256 let typ = char::from(f.type_());
257 if err_field_typs.contains(&typ) {
258 Ok(Some(ErrorField {
259 typ,
260 value: String::from_utf8_lossy(f.value_bytes())
261 .into_owned(),
262 }))
263 } else {
264 Ok(None)
265 }
266 })
267 .collect()
268 .unwrap(),
269 })?,
270 ),
271 Message::CopyOutResponse(body) => (
272 "CopyOut",
273 serde_json::to_string(&CopyOut {
274 format: format_name(body.format()),
275 column_formats: body
276 .column_formats()
277 .map(|format| Ok(format_name(format)))
278 .collect()
279 .unwrap(),
280 })?,
281 ),
282 Message::CopyInResponse(body) => (
283 "CopyIn",
284 serde_json::to_string(&CopyOut {
285 format: format_name(body.format()),
286 column_formats: body
287 .column_formats()
288 .map(|format| Ok(format_name(format)))
289 .collect()
290 .unwrap(),
291 })?,
292 ),
293 Message::CopyData(body) => (
294 "CopyData",
295 serde_json::to_string(
296 &std::str::from_utf8(body.data())
297 .map(|s| s.to_string())
298 .unwrap_or_else(|_| format!("{:?}", body.data())),
299 )?,
300 ),
301 Message::CopyDone => ("CopyDone", "".to_string()),
302 Message::ParameterDescription(body) => (
303 "ParameterDescription",
304 serde_json::to_string(&ParameterDescription {
305 parameters: body.parameters().collect().unwrap(),
306 })?,
307 ),
308 Message::ParameterStatus(body) => {
309 let name = body.name()?;
310 if !parameter_status.contains(name) {
311 continue;
312 }
313 (
314 "ParameterStatus",
315 serde_json::to_string(&ParameterStatus {
316 name: name.to_string(),
317 value: body.value()?.to_string(),
318 })?,
319 )
320 }
321 Message::NoData => ("NoData", "".to_string()),
322 Message::EmptyQueryResponse => ("EmptyQueryResponse", "".to_string()),
323 _ => ("UNKNOWN", format!("'{}'", ch)),
324 };
325 if self.verbose {
326 println!("RECV {}: {:?}", ch, typ);
327 }
328 if ignore.contains(typ) {
329 continue;
330 }
331 let mut s = typ.to_string();
332 if !args.is_empty() {
333 s.push(' ');
334 s.push_str(&args);
335 }
336 msgs.push(s);
337 if expect == typ {
338 break;
339 }
340 }
341 }
342 Ok(msgs)
343 }
344 pub fn recv(&mut self) -> anyhow::Result<(char, Message)> {
348 let mut buf = [0; 1024];
349 let until = Instant::now();
350 loop {
351 if until.elapsed() > self.timeout {
352 bail!("timeout after {:?} waiting for new message", self.timeout);
353 }
354 let mut ch: char = '0';
355 if self.recv_buf.len() > 0 {
356 ch = char::from(self.recv_buf[0]);
357 }
358 if let Some(msg) = Message::parse(&mut self.recv_buf)? {
359 return Ok((ch, msg));
360 };
361 let sz = match self.stream.read(&mut buf) {
363 Ok(n) => n,
364 Err(e) if e.kind() == ErrorKind::Interrupted => continue,
367 Err(e) => return Err(anyhow!(e)),
368 };
369 self.recv_buf.extend_from_slice(&buf[..sz]);
370 }
371 }
372}
373
374const DEFAULT_CONN: &str = "";
375
376pub struct PgTest {
377 addr: String,
378 user: String,
379 timeout: Duration,
380 conns: BTreeMap<String, PgConn>,
381 verbose: bool,
382}
383
384impl PgTest {
385 pub fn new(addr: String, user: String, timeout: Duration) -> anyhow::Result<Self> {
386 let verbose = std::env::var_os("PGTEST_VERBOSE").is_some();
387 let conn = PgConn::new(&addr, &user, timeout.clone(), verbose, vec![])?;
388 let mut conns = BTreeMap::new();
389 conns.insert(DEFAULT_CONN.to_string(), conn);
390
391 Ok(PgTest {
392 addr,
393 user,
394 timeout,
395 conns,
396 verbose,
397 })
398 }
399
400 fn get_conn(
403 &mut self,
404 name: Option<String>,
405 options: Vec<(&str, &str)>,
406 ) -> anyhow::Result<&mut PgConn> {
407 let name = name.unwrap_or_else(|| DEFAULT_CONN.to_string());
408 if !self.conns.contains_key(&name) {
409 let conn = PgConn::new(
410 &self.addr,
411 &self.user,
412 self.timeout.clone(),
413 self.verbose,
414 options,
415 )?;
416 self.conns.insert(name.clone(), conn);
417 }
418 Ok(self.conns.get_mut(&name).expect("must exist"))
419 }
420
421 pub fn send<F: Fn(&mut BytesMut)>(
422 &mut self,
423 conn: Option<String>,
424 options: Vec<(&str, &str)>,
425 f: F,
426 ) -> anyhow::Result<()> {
427 let conn = self.get_conn(conn, options)?;
428 conn.send(f)
429 }
430
431 pub fn until(
432 &mut self,
433 conn: Option<String>,
434 options: Vec<(&str, &str)>,
435 until: Vec<&str>,
436 err_field_typs: Vec<char>,
437 ignore: BTreeSet<String>,
438 parameter_status: &BTreeSet<String>,
439 ) -> anyhow::Result<Vec<String>> {
440 let conn = self.get_conn(conn, options)?;
441 conn.until(until, err_field_typs, ignore, parameter_status)
442 }
443}
444
445#[derive(Serialize)]
448pub struct ReadyForQuery {
449 pub status: String,
450}
451
452#[derive(Serialize)]
453pub struct RowDescription {
454 pub fields: Vec<Field>,
455}
456
457#[derive(Serialize)]
458pub struct Field {
459 pub name: String,
460}
461
462#[derive(Serialize)]
463pub struct DataRow {
464 pub fields: Vec<String>,
465}
466
467#[derive(Serialize)]
468pub struct CopyOut {
469 pub format: String,
470 pub column_formats: Vec<String>,
471}
472
473#[derive(Serialize)]
474pub struct ParameterDescription {
475 parameters: Vec<u32>,
476}
477
478#[derive(Serialize)]
479pub struct CommandComplete {
480 pub tag: String,
481}
482
483#[derive(Serialize)]
484pub struct ParameterStatus {
485 pub name: String,
486 pub value: String,
487}
488
489#[derive(Serialize)]
490pub struct ErrorResponse {
491 pub fields: Vec<ErrorField>,
492}
493
494#[derive(Serialize)]
495pub struct ErrorField {
496 pub typ: char,
497 pub value: String,
498}
499
500impl Drop for PgTest {
501 fn drop(&mut self) {
502 for conn in self.conns.values_mut() {
503 let _ = conn.send(frontend::terminate);
504 }
505 }
506}
507
508fn format_name<T>(format: T) -> String
509where
510 T: Copy + TryInto<u16> + fmt::Display,
511{
512 match format.try_into() {
513 Ok(0) => "text".to_string(),
514 Ok(1) => "binary".to_string(),
515 _ => format!("unknown: {}", format),
516 }
517}
518
519pub fn walk(addr: String, user: String, timeout: Duration, dir: &str) {
520 datadriven::walk(dir, |tf| run_test(tf, addr.clone(), user.clone(), timeout));
521}
522
523pub fn run_test(tf: &mut datadriven::TestFile, addr: String, user: String, timeout: Duration) {
524 let mut pgt = PgTest::new(addr, user, timeout).unwrap();
525 tf.run(|tc| -> String {
526 let lines = tc.input.lines();
527 let mut args = tc.args.clone();
528 let conn: Option<String> = args
529 .remove("conn")
530 .map(|args| Some(args.into_first()))
531 .unwrap_or(None);
532 let mut options: Vec<(&str, &str)> = Vec::new();
533 let cluster = args.remove("cluster");
534 if let Some(cluster) = &cluster {
535 let cluster = cluster.into_first();
536 options.push(("cluster", cluster.as_str()));
537 }
538 match tc.directive.as_str() {
539 "send" => {
540 for line in lines {
541 if pgt.verbose {
542 println!("SEND {}", line);
543 }
544 let mut line = line.splitn(2, ' ');
545 let typ = line.next().unwrap_or("");
546 let args = line.next().unwrap_or("{}");
547 pgt.send(conn.clone(), options.clone(), |buf| match typ {
548 "Query" => {
549 let v: Query = serde_json::from_str(args).unwrap();
550 frontend::query(&v.query, buf).unwrap();
551 }
552 "Parse" => {
553 let v: Parse = serde_json::from_str(args).unwrap();
554 frontend::parse(
555 &v.name.unwrap_or_else(|| "".into()),
556 &v.query,
557 vec![],
558 buf,
559 )
560 .unwrap();
561 }
562 "Sync" => frontend::sync(buf),
563 "Bind" => {
564 let v: Bind = serde_json::from_str(args).unwrap();
565 let values: Vec<Vec<u8>> = match v.binary_values {
571 Some(binary_values) => binary_values,
572 None => v
573 .values
574 .unwrap_or_default()
575 .into_iter()
576 .map(String::into_bytes)
577 .collect(),
578 };
579 if frontend::bind(
580 &v.portal.unwrap_or_else(|| "".into()),
581 &v.statement.unwrap_or_else(|| "".into()),
582 v.param_formats.unwrap_or_default(), values, |bytes: Vec<u8>, buf| {
585 buf.put_slice(&bytes);
586 Ok(IsNull::No)
587 }, v.result_formats.unwrap_or_default(),
589 buf,
590 )
591 .is_err()
592 {
593 panic!("bind error");
594 }
595 }
596 "Describe" => {
597 let v: Describe = serde_json::from_str(args).unwrap();
598 frontend::describe(
599 v.variant.unwrap_or_else(|| "S".into()).as_bytes()[0],
600 &v.name.unwrap_or_else(|| "".into()),
601 buf,
602 )
603 .unwrap();
604 }
605 "Execute" => {
606 let v: Execute = serde_json::from_str(args).unwrap();
607 frontend::execute(
608 &v.portal.unwrap_or_else(|| "".into()),
609 v.max_rows.unwrap_or(0),
610 buf,
611 )
612 .unwrap();
613 }
614 "CopyData" => {
615 let v: String = serde_json::from_str(args).unwrap();
616 frontend::CopyData::new(v.as_bytes()).unwrap().write(buf);
617 }
618 "CopyDone" => {
619 frontend::copy_done(buf);
620 }
621 "CopyFail" => {
622 let v: String = serde_json::from_str(args).unwrap();
623 frontend::copy_fail(&v, buf).unwrap();
624 }
625 _ => panic!("unknown message type {}", typ),
626 })
627 .unwrap();
628 }
629 "".to_string()
630 }
631 "until" => {
632 let err_field_typs = if let Some(_) = args.remove("no_error_fields") {
636 vec![]
637 } else {
638 match args.remove("err_field_typs") {
639 Some(typs) => typs.join("").chars().collect(),
640 None => vec!['C', 'S', 'M'],
641 }
642 };
643 let mut ignore = BTreeSet::new();
644 if let Some(values) = args.remove("ignore") {
645 for v in values {
646 ignore.insert(v);
647 }
648 }
649 let parameter_status: BTreeSet<String> = args
650 .remove("parameter_status")
651 .unwrap_or_default()
652 .into_iter()
653 .collect();
654 if !args.is_empty() {
655 panic!("extra until arguments: {:?}", args);
656 }
657 format!(
658 "{}\n",
659 pgt.until(
660 conn,
661 options,
662 lines.collect(),
663 err_field_typs,
664 ignore,
665 ¶meter_status,
666 )
667 .unwrap()
668 .join("\n")
669 )
670 }
671 _ => panic!("unknown directive {}", tc.input),
672 }
673 })
674}
675
676#[derive(Deserialize)]
679#[serde(deny_unknown_fields)]
680pub struct Query {
681 pub query: String,
682}
683
684#[derive(Deserialize)]
685#[serde(deny_unknown_fields)]
686pub struct Parse {
687 pub name: Option<String>,
688 pub query: String,
689}
690
691#[derive(Deserialize)]
692#[serde(deny_unknown_fields)]
693pub struct Bind {
694 pub portal: Option<String>,
695 pub statement: Option<String>,
696 pub values: Option<Vec<String>>,
697 pub param_formats: Option<Vec<i16>>,
700 pub binary_values: Option<Vec<Vec<u8>>>,
703 pub result_formats: Option<Vec<i16>>,
704}
705
706#[derive(Deserialize)]
707#[serde(deny_unknown_fields)]
708pub struct Execute {
709 pub portal: Option<String>,
710 pub max_rows: Option<i32>,
711}
712
713#[derive(Deserialize)]
714#[serde(deny_unknown_fields)]
715pub struct Describe {
716 pub variant: Option<String>,
717 pub name: Option<String>,
718}