github.com/dolthub/go-mysql-server@v0.18.0/sql/analyzer/check_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 analyzer 16 17 import ( 18 "github.com/dolthub/go-mysql-server/sql" 19 "github.com/dolthub/go-mysql-server/sql/expression" 20 "github.com/dolthub/go-mysql-server/sql/expression/function" 21 "github.com/dolthub/go-mysql-server/sql/plan" 22 "github.com/dolthub/go-mysql-server/sql/transform" 23 ) 24 25 // validateCheckConstraints validates DDL nodes that create table check constraints, such as CREATE TABLE and 26 // ALTER TABLE statements. 27 // 28 // TODO: validateCheckConstraints doesn't currently do any type validation on the check and will allow you to create 29 // checks that will never evaluate correctly. 30 func validateCheckConstraints(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Scope, sel RuleSelector) (sql.Node, transform.TreeIdentity, error) { 31 switch n := n.(type) { 32 case *plan.CreateCheck: 33 return validateCreateCheckNode(n) 34 case *plan.CreateTable: 35 return validateCreateTableChecks(ctx, a, n, scope) 36 } 37 38 return n, transform.SameTree, nil 39 } 40 41 func validateCreateTableChecks(ctx *sql.Context, a *Analyzer, n *plan.CreateTable, scope *plan.Scope) (sql.Node, transform.TreeIdentity, error) { 42 columns, err := indexColumns(ctx, a, n, scope) 43 if err != nil { 44 return nil, transform.SameTree, err 45 } 46 47 transform.InspectExpressions(n, func(e sql.Expression) bool { 48 if err != nil { 49 return false 50 } 51 52 switch e := e.(type) { 53 case *expression.Wrapper, nil: 54 // column defaults, no need to inspect these 55 return false 56 default: 57 // check expressions, must be validated 58 // TODO: would be better to wrap these in something else to be able to identify them better 59 err = checkExpressionValid(e) 60 if err != nil { 61 return false 62 } 63 64 switch e := e.(type) { 65 case column: 66 col := newTableCol(e.Table(), e.Name()) 67 if _, ok := columns[col]; !ok { 68 if _, ok := columns[newTableCol("", e.Name())]; !ok { 69 err = sql.ErrTableColumnNotFound.New(e.Table(), e.Name()) 70 return false 71 } 72 } 73 } 74 75 return true 76 } 77 }) 78 79 if err != nil { 80 return nil, transform.SameTree, err 81 } 82 83 return n, transform.SameTree, nil 84 } 85 86 func validateCreateCheckNode(ct *plan.CreateCheck) (sql.Node, transform.TreeIdentity, error) { 87 err := checkExpressionValid(ct.Check.Expr) 88 if err != nil { 89 return nil, transform.SameTree, err 90 } 91 92 return ct, transform.SameTree, nil 93 } 94 95 func checkExpressionValid(e sql.Expression) error { 96 var err error 97 sql.Inspect(e, func(e sql.Expression) bool { 98 switch e := e.(type) { 99 case *function.GetLock, *function.IsUsedLock, *function.IsFreeLock, function.ReleaseAllLocks, *function.ReleaseLock: 100 err = sql.ErrInvalidConstraintFunctionNotSupported.New(e.String()) 101 return false 102 case sql.FunctionExpression: 103 if ndf, ok := e.(sql.NonDeterministicExpression); ok && ndf.IsNonDeterministic() { 104 err = sql.ErrInvalidConstraintFunctionNotSupported.New(e.String()) 105 } 106 return false 107 case *plan.Subquery: 108 err = sql.ErrInvalidConstraintSubqueryNotSupported.New(e.String()) 109 return false 110 } 111 return true 112 }) 113 return err 114 }