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// Copyright Materialize, Inc. and contributors. All rights reserved.
11//
12// Use of this software is governed by the Business Source License
13// included in the LICENSE file.
14//
15// As of the Change Date specified in that file, in accordance with
16// the Business Source License, use of this software will be governed
17// by the Apache License, Version 2.0.
1819use std::fmt;
2021use mz_ore::str::{StrExt, separated};
22use mz_repr::ColumnName;
2324use crate::catalog::ObjectType;
2526/// Notices that can occur in the adapter layer.
27///
28/// These are diagnostic warnings or informational messages that are not
29/// severe enough to warrant failing a query entirely.
30#[derive(Clone, Debug, Eq, PartialEq)]
31pub enum PlanNotice {
32 ObjectDoesNotExist {
33 name: String,
34 object_type: ObjectType,
35 },
36 ColumnAlreadyExists {
37 column_name: String,
38 object_name: String,
39 },
40 UpsertSinkKeyNotEnforced {
41 key: Vec<ColumnName>,
42 name: String,
43 },
44}
4546impl PlanNotice {
47/// Reports additional details about the notice, if any are available.
48pub fn detail(&self) -> Option<String> {
49match self {
50 PlanNotice::UpsertSinkKeyNotEnforced { key, name } => {
51let details = format!(
52"Materialize did not validate that the specified upsert envelope key ({}) \
53 was a unique key of the underlying relation {}. If this key is not unique, \
54 the sink might produce multiple updates for the same key at the same time, \
55 which may confuse downstream consumers.",
56 separated(", ", key.iter().map(|c| c.as_str().quoted())),
57 name.quoted()
58 );
59Some(details)
60 }
61_ => None,
62 }
63 }
6465/// Reports a hint for the user about how the notice could be addressed.
66pub fn hint(&self) -> Option<String> {
67match self {
68 PlanNotice::UpsertSinkKeyNotEnforced { .. } => {
69Some("See: https://materialize.com/s/sink-key-selection".into())
70 }
71_ => None,
72 }
73 }
74}
7576impl fmt::Display for PlanNotice {
77fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78match self {
79 PlanNotice::ObjectDoesNotExist { name, object_type } => {
80write!(
81 f,
82"{} {} does not exist, skipping",
83 object_type,
84 name.quoted()
85 )
86 }
87 PlanNotice::ColumnAlreadyExists {
88 column_name,
89 object_name,
90 } => {
91write!(
92 f,
93"column {} of relation {} already exists, skipping",
94 column_name.quoted(),
95 object_name.quoted()
96 )
97 }
98 PlanNotice::UpsertSinkKeyNotEnforced { .. } => {
99write!(f, "upsert key not validated to be unique")
100 }
101 }
102 }
103}