github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/pgwire/pgerror/constraint_name.go (about)

     1  // Copyright 2020 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     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, included in the file
     9  // licenses/APL.txt.
    10  
    11  package pgerror
    12  
    13  import (
    14  	"context"
    15  	"fmt"
    16  
    17  	"github.com/cockroachdb/errors"
    18  	"github.com/cockroachdb/errors/errorspb"
    19  	"github.com/gogo/protobuf/proto"
    20  )
    21  
    22  // WithConstraintName decorates the error with a severity.
    23  func WithConstraintName(err error, constraint string) error {
    24  	if err == nil {
    25  		return nil
    26  	}
    27  
    28  	return &withConstraintName{cause: err, constraint: constraint}
    29  }
    30  
    31  // GetConstraintName attempts to unwrap and find a Severity.
    32  func GetConstraintName(err error) string {
    33  	if c := (*withConstraintName)(nil); errors.As(err, &c) {
    34  		return c.constraint
    35  	}
    36  	return ""
    37  }
    38  
    39  type withConstraintName struct {
    40  	cause      error
    41  	constraint string
    42  }
    43  
    44  var _ error = (*withConstraintName)(nil)
    45  var _ errors.SafeDetailer = (*withConstraintName)(nil)
    46  var _ fmt.Formatter = (*withConstraintName)(nil)
    47  var _ errors.SafeFormatter = (*withConstraintName)(nil)
    48  
    49  func (w *withConstraintName) Error() string { return w.cause.Error() }
    50  func (w *withConstraintName) Cause() error  { return w.cause }
    51  func (w *withConstraintName) Unwrap() error { return w.cause }
    52  func (w *withConstraintName) SafeDetails() []string {
    53  	// The constraint name is considered PII.
    54  	return nil
    55  }
    56  
    57  func (w *withConstraintName) Format(s fmt.State, verb rune) { errors.FormatError(w, s, verb) }
    58  
    59  func (w *withConstraintName) SafeFormatError(p errors.Printer) (next error) {
    60  	if p.Detail() {
    61  		p.Printf("constraint name: %s", w.constraint)
    62  	}
    63  	return w.cause
    64  }
    65  
    66  func encodeWithConstraintName(_ context.Context, err error) (string, []string, proto.Message) {
    67  	w := err.(*withConstraintName)
    68  	return "", nil, &errorspb.StringPayload{Msg: w.constraint}
    69  }
    70  
    71  // decodeWithConstraintName is a custom decoder that will be used when decoding
    72  // withConstraintName error objects.
    73  // Note that as the last argument it takes proto.Message (and not
    74  // protoutil.Message which is required by linter) because the latter brings in
    75  // additional dependencies into this package and the former is sufficient here.
    76  func decodeWithConstraintName(
    77  	_ context.Context, cause error, _ string, _ []string, payload proto.Message,
    78  ) error {
    79  	m, ok := payload.(*errorspb.StringPayload)
    80  	if !ok {
    81  		// If this ever happens, this means some version of the library
    82  		// (presumably future) changed the payload type, and we're
    83  		// receiving this here. In this case, give up and let
    84  		// DecodeError use the opaque type.
    85  		return nil
    86  	}
    87  	return &withConstraintName{cause: cause, constraint: m.Msg}
    88  }
    89  
    90  func init() {
    91  	key := errors.GetTypeKey((*withConstraintName)(nil))
    92  	errors.RegisterWrapperEncoder(key, encodeWithConstraintName)
    93  	errors.RegisterWrapperDecoder(key, decodeWithConstraintName)
    94  }