github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/alter_check.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 plan 16 17 import ( 18 "fmt" 19 20 "gopkg.in/src-d/go-errors.v1" 21 22 "github.com/dolthub/go-mysql-server/sql" 23 "github.com/dolthub/go-mysql-server/sql/expression" 24 "github.com/dolthub/go-mysql-server/sql/transform" 25 ) 26 27 var ( 28 // ErrNoCheckConstraintSupport is returned when the table does not support CONSTRAINT CHECK operations. 29 ErrNoCheckConstraintSupport = errors.NewKind("the table does not support check constraint operations: %s") 30 31 // ErrCheckViolated is returned when the check constraint evaluates to false 32 ErrCheckViolated = errors.NewKind("check constraint %s is violated.") 33 ) 34 35 type CreateCheck struct { 36 ddlNode 37 Table *ResolvedTable 38 Check *sql.CheckConstraint 39 } 40 41 var _ sql.Node = (*CreateCheck)(nil) 42 var _ sql.CollationCoercible = (*CreateCheck)(nil) 43 44 type DropCheck struct { 45 ddlNode 46 Table *ResolvedTable 47 Name string 48 } 49 50 var _ sql.Node = (*DropCheck)(nil) 51 var _ sql.CollationCoercible = (*DropCheck)(nil) 52 53 func NewAlterAddCheck(table *ResolvedTable, check *sql.CheckConstraint) *CreateCheck { 54 return &CreateCheck{ 55 ddlNode: ddlNode{table.SqlDatabase}, 56 Table: table, 57 Check: check, 58 } 59 } 60 61 func NewAlterDropCheck(table *ResolvedTable, name string) *DropCheck { 62 return &DropCheck{ 63 ddlNode: ddlNode{table.SqlDatabase}, 64 Table: table, 65 Name: name, 66 } 67 } 68 69 // Expressions implements the sql.Expressioner interface. 70 func (c *CreateCheck) Expressions() []sql.Expression { 71 return []sql.Expression{c.Check.Expr} 72 } 73 74 // Resolved implements the Resolvable interface. 75 func (c *CreateCheck) Resolved() bool { 76 return c.Check.Expr.Resolved() 77 } 78 79 func (c *CreateCheck) IsReadOnly() bool { 80 return false 81 } 82 83 // WithExpressions implements the sql.Expressioner interface. 84 func (c *CreateCheck) WithExpressions(exprs ...sql.Expression) (sql.Node, error) { 85 if len(exprs) != 1 { 86 return nil, fmt.Errorf("expected one expression, got: %d", len(exprs)) 87 } 88 89 nc := *c 90 nc.Check.Expr = exprs[0] 91 return &nc, nil 92 } 93 94 // WithChildren implements the Node interface. 95 func (c *CreateCheck) WithChildren(children ...sql.Node) (sql.Node, error) { 96 if len(children) != 1 { 97 return nil, sql.ErrInvalidChildrenNumber.New(c, len(children), 1) 98 } 99 return NewAlterAddCheck(children[0].(*ResolvedTable), c.Check), nil 100 } 101 102 func (c *CreateCheck) Children() []sql.Node { 103 return []sql.Node{c.Table} 104 } 105 106 // CheckPrivileges implements the interface sql.Node. 107 func (c *CreateCheck) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 108 db := c.Table.Database() 109 subject := sql.PrivilegeCheckSubject{ 110 Database: CheckPrivilegeNameForDatabase(db), 111 Table: getTableName(c.Table), 112 } 113 return opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation(subject, sql.PrivilegeType_Alter)) 114 } 115 116 // CollationCoercibility implements the interface sql.CollationCoercible. 117 func (c *CreateCheck) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 118 return sql.Collation_binary, 7 119 } 120 121 func (c *CreateCheck) Schema() sql.Schema { return nil } 122 123 func (c CreateCheck) String() string { 124 pr := sql.NewTreePrinter() 125 _ = pr.WriteNode("AddCheck(%s)", c.Check.Name) 126 _ = pr.WriteChildren( 127 fmt.Sprintf("Table(%s)", c.Table.Name()), 128 fmt.Sprintf("Expr(%s)", c.Check.Expr.String()), 129 ) 130 return pr.String() 131 } 132 133 func (d *DropCheck) Children() []sql.Node { 134 return []sql.Node{d.Table} 135 } 136 137 // WithChildren implements the Node interface. 138 func (d *DropCheck) WithChildren(children ...sql.Node) (sql.Node, error) { 139 if len(children) != 1 { 140 return nil, sql.ErrInvalidChildrenNumber.New(d, len(children), 1) 141 } 142 return NewAlterDropCheck(children[0].(*ResolvedTable), d.Name), nil 143 } 144 145 // CheckPrivileges implements the interface sql.Node. 146 func (d *DropCheck) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 147 db := d.Table.Database() 148 subject := sql.PrivilegeCheckSubject{ 149 Database: CheckPrivilegeNameForDatabase(db), 150 Table: getTableName(d.Table), 151 } 152 153 return opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation(subject, sql.PrivilegeType_Alter)) 154 } 155 156 // CollationCoercibility implements the interface sql.CollationCoercible. 157 func (d *DropCheck) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 158 return sql.Collation_binary, 7 159 } 160 161 func (d *DropCheck) Schema() sql.Schema { return nil } 162 163 func (d *DropCheck) IsReadOnly() bool { return false } 164 165 func (d DropCheck) String() string { 166 pr := sql.NewTreePrinter() 167 _ = pr.WriteNode("DropCheck(%s)", d.Name) 168 _ = pr.WriteChildren(fmt.Sprintf("Table(%s)", d.Table.Name())) 169 return pr.String() 170 } 171 172 func NewCheckDefinition(ctx *sql.Context, check *sql.CheckConstraint) (*sql.CheckDefinition, error) { 173 // When transforming an analyzed CheckConstraint into a CheckDefinition (for storage), we strip off any table 174 // qualifiers that got resolved during analysis. This is to naively match the MySQL behavior, which doesn't print 175 // any table qualifiers in check expressions. 176 unqualifiedCols, _, err := transform.Expr(check.Expr, func(e sql.Expression) (sql.Expression, transform.TreeIdentity, error) { 177 gf, ok := e.(*expression.GetField) 178 if ok { 179 return expression.NewGetField(gf.Index(), gf.Type(), gf.Name(), gf.IsNullable()), transform.NewTree, nil 180 } 181 return e, transform.SameTree, nil 182 }) 183 if err != nil { 184 return nil, err 185 } 186 187 return &sql.CheckDefinition{ 188 Name: check.Name, 189 CheckExpression: fmt.Sprintf("%s", unqualifiedCols), 190 Enforced: check.Enforced, 191 }, nil 192 } 193 194 // DropConstraint is a temporary node to handle dropping a named constraint on a table. The type of the constraint is 195 // not known, and is determined during analysis. 196 type DropConstraint struct { 197 UnaryNode 198 Name string 199 } 200 201 var _ sql.Node = (*DropConstraint)(nil) 202 var _ sql.CollationCoercible = (*DropConstraint)(nil) 203 204 func (d *DropConstraint) String() string { 205 tp := sql.NewTreePrinter() 206 _ = tp.WriteNode("DropConstraint(%s)", d.Name) 207 _ = tp.WriteChildren(d.UnaryNode.Child.String()) 208 return tp.String() 209 } 210 211 func (d DropConstraint) WithChildren(children ...sql.Node) (sql.Node, error) { 212 if len(children) != 1 { 213 return nil, sql.ErrInvalidChildrenNumber.New(d, len(children), 1) 214 } 215 216 nd := &d 217 nd.UnaryNode = UnaryNode{children[0]} 218 return nd, nil 219 } 220 221 // CheckPrivileges implements the interface sql.Node. 222 func (d *DropConstraint) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 223 db := GetDatabase(d.Child) 224 subject := sql.PrivilegeCheckSubject{ 225 Database: CheckPrivilegeNameForDatabase(db), 226 Table: getTableName(d.Child), 227 } 228 return opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation(subject, sql.PrivilegeType_Alter)) 229 } 230 231 func (d *DropConstraint) IsReadOnly() bool { return false } 232 233 // CollationCoercibility implements the interface sql.CollationCoercible. 234 func (d *DropConstraint) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 235 return sql.Collation_binary, 7 236 } 237 238 // NewDropConstraint returns a new DropConstraint node 239 func NewDropConstraint(table *UnresolvedTable, name string) *DropConstraint { 240 return &DropConstraint{ 241 UnaryNode: UnaryNode{table}, 242 Name: name, 243 } 244 }