mz_transform/notice/
index_already_exists.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Hosts [`IndexAlreadyExists`].
11
12use std::collections::BTreeSet;
13use std::fmt;
14
15use mz_expr::MirScalarExpr;
16use mz_expr::explain::{HumanizedNotice, HumanizerMode};
17use mz_ore::str::separated;
18use mz_repr::GlobalId;
19use mz_repr::explain::ExprHumanizer;
20
21use crate::notice::{ActionKind, OptimizerNoticeApi};
22
23/// Trying to re-create an index that already exists.
24#[derive(Clone, Debug, Eq, PartialEq, Hash)]
25pub struct IndexAlreadyExists {
26    /// The id of the identical index.
27    pub index_id: GlobalId,
28    /// The key of the index.
29    pub index_key: Vec<MirScalarExpr>,
30    /// The id of the object that the index is on.
31    pub index_on_id: GlobalId,
32    /// The id the index that duplicates existing indexes.
33    pub exported_index_id: GlobalId,
34}
35
36impl OptimizerNoticeApi for IndexAlreadyExists {
37    fn dependencies(&self) -> BTreeSet<GlobalId> {
38        BTreeSet::from([self.index_id, self.index_on_id])
39    }
40
41    fn fmt_message(
42        &self,
43        f: &mut fmt::Formatter<'_>,
44        humanizer: &dyn ExprHumanizer,
45        redacted: bool,
46    ) -> fmt::Result {
47        let exported_index_name = humanizer
48            .humanize_id(self.exported_index_id)
49            .unwrap_or_else(|| self.exported_index_id.to_string());
50        let index_name = humanizer
51            .humanize_id(self.index_id)
52            .unwrap_or_else(|| self.index_id.to_string());
53        let index_on_id_name = humanizer
54            .humanize_id_unqualified(self.index_on_id)
55            .unwrap_or_else(|| self.index_on_id.to_string());
56
57        let mode = HumanizedNotice::new(redacted);
58        let col_names = humanizer.column_names_for_id(self.index_on_id);
59        let col_names = col_names.as_ref();
60        let index_key = separated(", ", mode.seq(&self.index_key, col_names));
61
62        write!(
63            f,
64            "Index {exported_index_name} is identical to {index_name}, which \
65             is also defined on {index_on_id_name}({index_key})."
66        )
67    }
68
69    fn fmt_hint(
70        &self,
71        f: &mut fmt::Formatter<'_>,
72        humanizer: &dyn ExprHumanizer,
73        redacted: bool,
74    ) -> fmt::Result {
75        let index_on_id_name = humanizer
76            .humanize_id_unqualified(self.index_on_id)
77            .unwrap_or_else(|| self.index_on_id.to_string());
78
79        let mode = HumanizedNotice::new(redacted);
80        let col_names = humanizer.column_names_for_id(self.index_on_id);
81        let col_names = col_names.as_ref();
82        let index_key = separated(", ", mode.seq(&self.index_key, col_names));
83
84        write!(
85            f,
86            "Please drop all indexes except the first index created on \
87             {index_on_id_name}({index_key}) and recreate all dependent objects."
88        )
89    }
90
91    fn fmt_action(
92        &self,
93        _f: &mut fmt::Formatter<'_>,
94        _humanizer: &dyn ExprHumanizer,
95        _redacted: bool,
96    ) -> fmt::Result {
97        Ok(())
98    }
99
100    fn action_kind(&self, _humanizer: &dyn ExprHumanizer) -> ActionKind {
101        ActionKind::None
102    }
103}