1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// Copyright Materialize, Inc. and contributors. All rights reserved.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0.

use anyhow::{bail, Context};
use mz_ore::option::OptionExt;
use tokio::process::Command;

use crate::action::{ControlFlow, State};
use crate::parser::BuiltinCommand;
use crate::util::text;

pub async fn run_execute(
    mut cmd: BuiltinCommand,
    state: &State,
) -> Result<ControlFlow, anyhow::Error> {
    let command = cmd.args.string("command")?;
    cmd.args.done()?;

    let expected_output = cmd.input.join("\n");
    let output = Command::new("psql")
        .args([
            // Ignore .psqlrc so that local execution of testdrive isn't
            // affected by it.
            "--no-psqlrc",
            "--pset",
            "footer=off",
            "--command",
            &command,
            &format!(
                "postgres://{}@{}",
                state.materialize.user, state.materialize.sql_addr
            ),
        ])
        .output()
        .await
        .context("execution of `psql` failed")?;
    if !output.status.success() {
        bail!(
            "psql reported failure with exit code {}: {}",
            output.status.code().display_or("unknown"),
            String::from_utf8_lossy(&output.stderr),
        );
    }
    let stdout = text::trim_trailing_space(&String::from_utf8_lossy(&output.stdout));
    if expected_output != stdout {
        text::print_diff(&expected_output, &*stdout);
        bail!("psql returned unexpected output (diff above)");
    }
    Ok(ControlFlow::Continue)
}