mz_testdrive/action/postgres/
execute.rs1use anyhow::{Context, anyhow, bail};
11use mz_ore::task;
12use tokio_postgres::Client;
13
14use crate::action::{BackgroundTask, ControlFlow, State};
15use crate::parser::BuiltinCommand;
16use crate::util::postgres::postgres_client;
17
18fn builtin_connection_url(state: &State, name: &str) -> Option<String> {
23 match name {
24 "mz_system" => Some(format!(
25 "postgres://mz_system:materialize@{}",
26 state.materialize.internal_sql_addr
27 )),
28 "materialize" => Some(format!(
29 "postgres://materialize:materialize@{}",
30 state.materialize.sql_addr
31 )),
32 _ => None,
33 }
34}
35
36async fn execute_input(cmd: BuiltinCommand, client: &Client) -> Result<(), anyhow::Error> {
37 for query in cmd.input {
38 println!(">> {}", query);
39 #[allow(clippy::disallowed_methods)]
42 client
43 .batch_execute(&query)
44 .await
45 .context("executing postgres query")?;
46 }
47 Ok(())
48}
49
50pub async fn run_execute(
51 mut cmd: BuiltinCommand,
52 state: &mut State,
53) -> Result<ControlFlow, anyhow::Error> {
54 let connection = cmd.args.string("connection")?;
55 let background = cmd.args.opt_bool("background")?.unwrap_or(false);
56 cmd.args.done()?;
57
58 match (connection.starts_with("postgres://"), background) {
59 (true, true) => {
60 let (client_inner, _) = postgres_client(&connection, state.default_timeout).await?;
61 let desc = cmd.input.first().cloned().unwrap_or_default();
62 let cancel_token = client_inner.cancel_token();
66 let handle = task::spawn(|| "postgres-execute", async move {
67 execute_input(cmd, &client_inner).await
68 });
69 state.background_tasks.push(BackgroundTask {
72 desc,
73 handle,
74 cancel_token,
75 url: connection,
76 });
77 }
78 (false, true) => bail!("cannot use 'background' arg with referenced connection"),
79 (true, false) => {
80 let (client_inner, _) = postgres_client(&connection, state.default_timeout).await?;
81 execute_input(cmd, &client_inner).await?;
82 }
83 (false, false) => {
84 if !state.postgres_clients.contains_key(&connection)
85 && let Some(url) = builtin_connection_url(state, &connection)
86 {
87 let (client, _) = postgres_client(&url, state.default_timeout).await?;
88 state.postgres_clients.insert(connection.clone(), client);
89 }
90 let client = state
91 .postgres_clients
92 .get(&connection)
93 .ok_or_else(|| anyhow!("connection '{}' not found", connection))?;
94 execute_input(cmd, client).await?;
95 }
96 }
97
98 Ok(ControlFlow::Continue)
99}