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.
910//! Hosts [`IndexAlreadyExists`].
1112use std::collections::BTreeSet;
13use std::fmt;
1415use mz_expr::MirScalarExpr;
16use mz_expr::explain::{HumanizedNotice, HumanizerMode};
17use mz_ore::str::separated;
18use mz_repr::GlobalId;
19use mz_repr::explain::ExprHumanizer;
2021use crate::notice::{ActionKind, OptimizerNoticeApi};
2223/// 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.
27pub index_id: GlobalId,
28/// The key of the index.
29pub index_key: Vec<MirScalarExpr>,
30/// The id of the object that the index is on.
31pub index_on_id: GlobalId,
32/// The id the index that duplicates existing indexes.
33pub exported_index_id: GlobalId,
34}
3536impl OptimizerNoticeApi for IndexAlreadyExists {
37fn dependencies(&self) -> BTreeSet<GlobalId> {
38 BTreeSet::from([self.index_id, self.index_on_id])
39 }
4041fn fmt_message(
42&self,
43 f: &mut fmt::Formatter<'_>,
44 humanizer: &dyn ExprHumanizer,
45 redacted: bool,
46 ) -> fmt::Result {
47let exported_index_name = humanizer
48 .humanize_id(self.exported_index_id)
49 .unwrap_or_else(|| self.exported_index_id.to_string());
50let index_name = humanizer
51 .humanize_id(self.index_id)
52 .unwrap_or_else(|| self.index_id.to_string());
53let index_on_id_name = humanizer
54 .humanize_id_unqualified(self.index_on_id)
55 .unwrap_or_else(|| self.index_on_id.to_string());
5657let mode = HumanizedNotice::new(redacted);
58let col_names = humanizer.column_names_for_id(self.index_on_id);
59let col_names = col_names.as_ref();
60let index_key = separated(", ", mode.seq(&self.index_key, col_names));
6162write!(
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 }
6869fn fmt_hint(
70&self,
71 f: &mut fmt::Formatter<'_>,
72 humanizer: &dyn ExprHumanizer,
73 redacted: bool,
74 ) -> fmt::Result {
75let index_on_id_name = humanizer
76 .humanize_id_unqualified(self.index_on_id)
77 .unwrap_or_else(|| self.index_on_id.to_string());
7879let mode = HumanizedNotice::new(redacted);
80let col_names = humanizer.column_names_for_id(self.index_on_id);
81let col_names = col_names.as_ref();
82let index_key = separated(", ", mode.seq(&self.index_key, col_names));
8384write!(
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 }
9091fn fmt_action(
92&self,
93 _f: &mut fmt::Formatter<'_>,
94 _humanizer: &dyn ExprHumanizer,
95 _redacted: bool,
96 ) -> fmt::Result {
97Ok(())
98 }
99100fn action_kind(&self, _humanizer: &dyn ExprHumanizer) -> ActionKind {
101 ActionKind::None
102 }
103}