github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/update_source.go (about) 1 // Copyright 2020-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 "strings" 19 20 "github.com/dolthub/go-mysql-server/sql/transform" 21 22 "github.com/dolthub/go-mysql-server/sql" 23 ) 24 25 // UpdateSource is the source of updates for an Update node. Its schema is the concatenation of the old and new rows, 26 // before and after being updated. 27 type UpdateSource struct { 28 UnaryNode 29 UpdateExprs []sql.Expression 30 Ignore bool 31 } 32 33 var _ sql.Node = (*UpdateSource)(nil) 34 var _ sql.CollationCoercible = (*UpdateSource)(nil) 35 36 // NewUpdateSource returns a new UpdateSource from the node and expressions given. 37 func NewUpdateSource(node sql.Node, ignore bool, updateExprs []sql.Expression) *UpdateSource { 38 return &UpdateSource{ 39 UnaryNode: UnaryNode{node}, 40 UpdateExprs: updateExprs, 41 Ignore: ignore, 42 } 43 } 44 45 // Expressions implements the sql.Expressioner interface. 46 func (u *UpdateSource) Expressions() []sql.Expression { 47 return u.UpdateExprs 48 } 49 50 func (u *UpdateSource) IsReadOnly() bool { 51 return true 52 } 53 54 // WithExpressions implements the sql.Expressioner interface. 55 func (u *UpdateSource) WithExpressions(newExprs ...sql.Expression) (sql.Node, error) { 56 if len(newExprs) != len(u.UpdateExprs) { 57 return nil, sql.ErrInvalidChildrenNumber.New(u, len(u.UpdateExprs), 1) 58 } 59 return NewUpdateSource(u.Child, u.Ignore, newExprs), nil 60 } 61 62 // Schema implements sql.Node. The schema of an update is a concatenation of the old and new rows. 63 func (u *UpdateSource) Schema() sql.Schema { 64 return append(u.Child.Schema(), u.Child.Schema()...) 65 } 66 67 // Resolved implements the Resolvable interface. 68 func (u *UpdateSource) Resolved() bool { 69 if !u.Child.Resolved() { 70 return false 71 } 72 for _, updateExpr := range u.UpdateExprs { 73 if !updateExpr.Resolved() { 74 return false 75 } 76 } 77 return true 78 } 79 80 func (u *UpdateSource) String() string { 81 tp := sql.NewTreePrinter() 82 var updateExprs []string 83 for _, e := range u.UpdateExprs { 84 updateExprs = append(updateExprs, e.String()) 85 } 86 _ = tp.WriteNode("UpdateSource(%s)", strings.Join(updateExprs, ",")) 87 _ = tp.WriteChildren(u.Child.String()) 88 return tp.String() 89 } 90 91 func (u *UpdateSource) DebugString() string { 92 pr := sql.NewTreePrinter() 93 var updateExprs []string 94 for _, e := range u.UpdateExprs { 95 updateExprs = append(updateExprs, sql.DebugString(e)) 96 } 97 _ = pr.WriteNode("UpdateSource(%s)", strings.Join(updateExprs, ",")) 98 _ = pr.WriteChildren(sql.DebugString(u.Child)) 99 return pr.String() 100 } 101 102 func (u *UpdateSource) GetChildSchema() (sql.Schema, error) { 103 if nodeHasJoin(u.Child) { 104 return u.Child.Schema(), nil 105 } 106 107 table, err := GetUpdatable(u.Child) 108 if err != nil { 109 return nil, err 110 } 111 112 return table.Schema(), nil 113 } 114 115 func nodeHasJoin(node sql.Node) bool { 116 hasJoinNode := false 117 transform.Inspect(node, func(node sql.Node) bool { 118 switch node.(type) { 119 case *JoinNode: 120 hasJoinNode = true 121 return false 122 default: 123 return true 124 } 125 }) 126 127 return hasJoinNode 128 } 129 130 func (u *UpdateSource) WithChildren(children ...sql.Node) (sql.Node, error) { 131 if len(children) != 1 { 132 return nil, sql.ErrInvalidChildrenNumber.New(u, len(children), 1) 133 } 134 return NewUpdateSource(children[0], u.Ignore, u.UpdateExprs), nil 135 } 136 137 // CheckPrivileges implements the interface sql.Node. 138 func (u *UpdateSource) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 139 return u.Child.CheckPrivileges(ctx, opChecker) 140 } 141 142 // CollationCoercibility implements the interface sql.CollationCoercible. 143 func (u *UpdateSource) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 144 return sql.GetCoercibility(ctx, u.Child) 145 }