github.com/dolthub/go-mysql-server@v0.18.0/sql/constraints.go (about)

     1  // Copyright 2021 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package sql
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  )
    21  
    22  // ForeignKeyConstraint declares a constraint between the columns of two tables.
    23  type ForeignKeyConstraint struct {
    24  	Name           string
    25  	Database       string
    26  	Table          string
    27  	Columns        []string
    28  	ParentDatabase string
    29  	ParentTable    string
    30  	ParentColumns  []string
    31  	OnUpdate       ForeignKeyReferentialAction
    32  	OnDelete       ForeignKeyReferentialAction
    33  	IsResolved     bool
    34  }
    35  
    36  // ForeignKeyReferentialAction is the behavior for this foreign key with the relevant action is performed on the foreign
    37  // table.
    38  type ForeignKeyReferentialAction string
    39  
    40  const (
    41  	ForeignKeyReferentialAction_DefaultAction ForeignKeyReferentialAction = "DEFAULT" // No explicit action was specified
    42  	ForeignKeyReferentialAction_Restrict      ForeignKeyReferentialAction = "RESTRICT"
    43  	ForeignKeyReferentialAction_Cascade       ForeignKeyReferentialAction = "CASCADE"
    44  	ForeignKeyReferentialAction_NoAction      ForeignKeyReferentialAction = "NO ACTION"
    45  	ForeignKeyReferentialAction_SetNull       ForeignKeyReferentialAction = "SET NULL"
    46  	ForeignKeyReferentialAction_SetDefault    ForeignKeyReferentialAction = "SET DEFAULT"
    47  )
    48  
    49  // IsSelfReferential returns whether this foreign key represents a self-referential foreign key.
    50  func (f ForeignKeyConstraint) IsSelfReferential() bool {
    51  	return strings.ToLower(f.Database) == strings.ToLower(f.ParentDatabase) &&
    52  		strings.ToLower(f.Table) == strings.ToLower(f.ParentTable)
    53  }
    54  
    55  func (f *ForeignKeyConstraint) DebugString() string {
    56  	return fmt.Sprintf(
    57  		"FOREIGN KEY %s (%s) REFERENCES %s (%s)",
    58  		f.Name,
    59  		strings.Join(f.Columns, ","),
    60  		f.ParentTable,
    61  		strings.Join(f.ParentColumns, ","),
    62  	)
    63  }
    64  
    65  // IsEquivalentToRestrict returns whether the referential action is equivalent to RESTRICT. In MySQL, although there are
    66  // a number of referential actions, the majority of them are functionally ignored and default to RESTRICT.
    67  func (f ForeignKeyReferentialAction) IsEquivalentToRestrict() bool {
    68  	switch f {
    69  	case ForeignKeyReferentialAction_Cascade, ForeignKeyReferentialAction_SetNull:
    70  		return false
    71  	default:
    72  		return true
    73  	}
    74  }
    75  
    76  // CheckDefinition defines a trigger. Integrators are not expected to parse or understand the trigger definitions,
    77  // but must store and return them when asked.
    78  type CheckDefinition struct {
    79  	Name            string // The name of this check. Check names in a database are unique.
    80  	CheckExpression string // String serialization of the check expression
    81  	Enforced        bool   // Whether this constraint is enforced
    82  }
    83  
    84  // CheckConstraint declares a boolean-eval constraint.
    85  type CheckConstraint struct {
    86  	Name     string
    87  	Expr     Expression
    88  	Enforced bool
    89  }
    90  
    91  type CheckConstraints []*CheckConstraint
    92  
    93  type CheckConstraintNode interface {
    94  	Node
    95  	Checks() CheckConstraints
    96  	WithChecks(CheckConstraints) Node
    97  }
    98  
    99  // ToExpressions returns the check expressions in these constraints as a slice of sql.Expression
   100  func (checks CheckConstraints) ToExpressions() []Expression {
   101  	exprs := make([]Expression, len(checks))
   102  	for i := range checks {
   103  		exprs[i] = checks[i].Expr
   104  	}
   105  	return exprs
   106  }
   107  
   108  // FromExpressions takes a slice of sql.Expression in the same order as these constraints, and returns a new slice of
   109  // constraints with the expressions given, holding names and other properties constant.
   110  func (checks CheckConstraints) FromExpressions(exprs []Expression) (CheckConstraints, error) {
   111  	if len(checks) != len(exprs) {
   112  		return nil, ErrInvalidChildrenNumber.New(checks, len(exprs), len(checks))
   113  	}
   114  
   115  	newChecks := make(CheckConstraints, len(checks))
   116  	for i := range exprs {
   117  		nc := *checks[i]
   118  		newChecks[i] = &nc
   119  		newChecks[i].Expr = exprs[i]
   120  	}
   121  
   122  	return newChecks, nil
   123  }
   124  
   125  func (c CheckConstraint) DebugString() string {
   126  	name := c.Name
   127  	if len(name) > 0 {
   128  		name += " "
   129  	}
   130  	not := ""
   131  	if !c.Enforced {
   132  		not = "not "
   133  	}
   134  	return fmt.Sprintf("%sCHECK %s %sENFORCED", name, DebugString(c.Expr), not)
   135  }